Custom helper with block - erb

I'm using the current release 4.3.3 of Middleman.
I'd like to define a custom helper which accepts a block. For the sake of simplicity, here's a nonsensical example of wrap_me which wraps the block content with the given tag.
It should be possible to implement this with capture_html provided by Padrino (which is explicitly mentioned in the Middleman docs):
module CustomHelpers
def wrap_me(tag, &block)
captured = capture_html(&block)
concat_content "<#{tag}>" + captured + "</#{tag}>"
end
end
Put to use in ERB:
<%= wrap_me('span') do %>
Hello
<% end %>
Now this raises a SyntaxError on line 274 of tilt-2.0.9/lib/tilt/template.rb which tries to eval a string. It appears, the capture is going beyond the "end".
What am I doing wrong here? How to use capture_html and concat_content if Tilt is preventing helpers from having blocks?
Thanks for your help!
(I'll ask the same question in the Middleman forum.)

Apparently, when using blocks, the equal sign has to be dropped. The following works:
<% wrap_me('span') do %>
Hello
<% end %>

Related

Jest - how to test if a component does not exist?

How do I check if a component is not present, i.e. that a specific component has not been rendered?
.contains receives a React Node or array of Nodes as an argument. Instead, use .find:
expect(wrapper.find('selector').exists()).toBeTruthy()
You can use enzymes contains to check if the component was rendered:
expect(component.contains(<ComponentName />)).toBe(false)
If you're using react-testing-library (I know the OP wasn't but I found this question via web search) then this will work:
expect(component.queryByText("Text I care about")).not.toBeInTheDocument();
You can query by Text, Role, and several others. See docs for more info.
Note: queryBy* will return null if it is not found. If you use getBy* then it will error out for elements not found.
Providing a slightly updated answer based on the documentation for enzyme-matchers's toExist. This will require you to install the enzyme-matchers package.
function Fixture() {
return (
<div>
<span className="foo" />
<span className="bar baz" />
</div>
);
}
const wrapper = mount(<Fixture />); // mount/render/shallow when applicable
expect(wrapper.find('span')).toExist();
expect(wrapper.find('ul')).not.toExist();
.contains does not expect a selector, unlike find. You can look at the length attribute of the ShallowWrapper
expect(wrapper.find('...')).toHaveLength(0)
I found I needed to use this syntax with Enzyme and Jest to test if a Connected Component existed in the rendered output.
We use Jest and Enzyme, and I've found the only good test is to import the sub-component and test this way:
expect(component.find(SubComponent).length).toEqual(0); // or (1) for exists, obvs
I tried all the other answers and none worked reliably.
If you are using react-testing-library, then this also will work:
expect(component.queryByText("Text I care about").toBeNull());
expect(within(component).queryByText("Text I care about")).toBeNull();
Note: In my case, I needed to use queryBy* because it doesn´t error out when the text element (that contains the text: Text I care about) does not exist. Therefore, I could evaluate whether there is an existence of a text component or not.

Bitbucket - Groovy Pre-receive Hook

I am trying to understand the following code snippet following site.
<% refChanges.getCommits(repository).each { commit -> %>
- ${commit.author.name} | ${commit.displayId} | ${commit.message} | ${commit.authorTimestamp}
<% } %>
The script is using a getCommits method, but when I look at the documentation for the RefChange interface I do not see any such method.
I consider myself an expert Java developer, but I have no workable knowledge in Groovy, so I assume that I am misunderstanding Groovy or the BitBucket documentation (or both).
In Groovy it's possible to add methods to a class or interface at run-time via meta-programming. Since the RefChange interface does not include getCommits(), it must be that the method is being added after-the-fact. Based on their example code, it looks like they're using the meta-class.
Where is getCommits()?
For example, in Groovy the Collection interface gets the method findAll() (along with many other methods). I can confirm this as follows:
assert Collection.metaClass.metaMethods*.name.contains('findAll') == true
The code above grabs the names of all the meta methods and then uses contains() to see if a match is found. You can confirm the same for getCommits() in a similar way:
assert Collection.metaClass.metaMethods*.name.contains('getCommits') == true
Note that I specified Collection rather than RefChange because refChanges is a Collection of RefChange. And so I think Atlasssian stuck getCommits() into Collection as a convenience method.
How does it work?
To understand what's going, I'll remove the templating code:
refChanges.getCommits(repository).each { commit ->
"${commit.author.name} | ${commit.displayId} | ${commit.message} | ${commit.authorTimestamp}"
}
getCommits() returns a Collection of com.atlassian.bitbucket.commit.Commit.
Object.each(Closure) is added by the Groovy GDK (yes, into the Object class) and it calls the Closure repeatedly; each time with an element of the Collection.
Although it's not apparent in the example code, the line within the each(Closure) is a GString. Basically the expressions within the ${...} are evaluated and the whole thing is concatenated into a String.

Static includes in nested namespaces using Mako

I'm trying this method to add static includes to my namespaces but I'm facing the problem that, static includes from nested namespaces are not included in the base template. To make the problem more concrete, below I post some example code:
base.mako
<!DOCTYPE html>
<head>
% for ns in context.namespaces.values():
% if hasattr(ns, 'includes'):
${ns.includes()}
% endif
% endfor
</head>
<body>
${next.body()}
</body>
</html>
child.mako
<%inherit file="base.mako"/>
<%namespace name="rb" file="buttons.mako"/>
${rb.render_buttons}
buttons.mako
<%namespace name="lib" file="lib.mako"/>
<%def name="includes()">
<script type="text/javascript" src="${request.static_url('project:static/lib.js')}"></script>
</%def>
<%def name="render_buttons()>
<button onclick="some_function_from_lib_js()">Click me!</button>
${lib.render_text()}
</%def>
lib.mako
<%def name="includes()">
<script type="text/javascript" src="${request.static_url('project:static/other.js')}"></script>
</%def>
<%def name="render_text()">
<button onclick="some_function_from_other_js()">No! Click me!</button>
</%def>
This is just an example but I hope it suffices to describe my problem.
There are syntax errors in the code you posted. Also, there are references to external (request for example) entities. Please always make sure your code is correct and works before posting.
The problem seems to be that context.namespaces is collection of namespaces declared only in templates in inheritance chain. This could be inferred from the following statement from docs:
Iterating the values of this dictionary will provide a Namespace
object for each time the <%namespace> tag was used, anywhere within
the inheritance chain.
Your inheritance chain consists from child.mako and base.mako only. Out of these only child.mako declares namespace (rb) and thus this is the only namespace in context.namespaces. You can see this easily if you insert ${ns.uri} after % for ns in context.namespaces.values(): line. This will render buttons.mako string alone in the output.
The solution in your case would be to look for includes defs not only in namespaces declared in templates in inheritance chain but also in namespaces declared by those namespaces. Something like
% for ns in context.namespaces.values():
% for ns2 in ns.context.namespaces.values():
% if hasattr(ns2, 'includes'):
${ns2.includes()}
% endif
% endfor
% if hasattr(ns, 'includes'):
${ns.includes()}
% endif
% endfor
However it does not work from what I see and don't know why.

hiera dealing with undefined variables in erb templates

I start using hiera for environment or machine specific variables but I am facing an issue when variable is not found nowhere. Desired behaviour is that shouldn't be included into template.
I did following:
In my manifest code
$yarn_app_mapreduce_am_command_opts=hiera('yarn.app.mapreduce.am.command-opts',undef)
and in erb template I have:
<% if !#yarn_app_mapreduce_am_command_opts.nil? %>
<property>
<name>yarn.app.mapreduce.am.command-opts</name>
<value><%= #yarn_app_mapreduce_am_command_opts %></value>
</property>
<%end %>
According to the documentation here safest is to test on nil. I tried several variants but non of them worked.
Could someone help?
This seems to be an issue with the hiera() function. I checked with the following manifest.
$without_hiera = undef
$with_hiera = hiera('undefined_key', undef)
$no_hiera_template = 'Without Hiera: <% if #without_hiera.nil? %>nil<% else %>not nil: "<%= #without_hiera %>"<% end %>'
$hiera_template = 'With Hiera: <% if #with_hiera.nil? %>nil<% else %>not nil: "<%= #with_hiera %>"<% end %>'
notify {
'hiera':
message => inline_template($hiera_template);
'no_hiera':
message => inline_template($no_hiera_template);
}
This yields:
Notice: Without Hiera: nil
Notice: /Stage[main]/Main/Notify[no_hiera]/message: defined 'message' as 'Without Hiera: nil'
Notice: With Hiera: not nil: ""
Notice: /Stage[main]/Main/Notify[hiera]/message: defined 'message' as 'With Hiera: not nil: ""'
The issue is known and has been discussed at length, but no acceptable fix has come forth yet. The problem is reproducible with the current master and puppet-4 branches.
Seeing as this will be difficult to fix, you are obviously in need of a workaround. The possibilities depend on your data.
If a value of boolean false (note that this is different from the String "false") is not ever sensible for your keys, you can make false the default and just test <% if ! #value -%> in your templates.
If the empty String is not ever a sensible value, you can make that the default, and test for it using <% if ! #value.to_s.empty? -%>
Finally, it might be possible for you to write your own wrapper around the hiera function, which overwrites an arbitrary default such as __KEY_NOT_FOUND__ to nil. Your mileage may vary. See the bug report for some pointers to previous work that may be of help.
It may also be helpful to find out whether one of the related bugs was moved to Jira, and to leave a vote and a note there that this is still an issue with Hiera.

Incorporate jenkins environment variables into groovy template for email notification

I have several environment variables defined for a project on jenkins, amongst which i want to incorporate some onto the email notification sent before and after build success.
But groovy.text.Template does not seem to accept these environment variables.
I have also used "Inject environment variables to the build process Help for feature: Inject environment variables to the build process" and defined my variable as follows
BUILD_NAME=${BUILD_NAME}
where BUILD_NAME is accepted as a parameter while i execute the build.
Please could someone help me on this.
If you are using the email-ext Jenkins plugin to send out emails, there is a "build" object that contains a lot of information about your Jenkins job.
I would do the following:
Print out the properties inside this object by adding the following code to your template:
<% println build.properties.collect{it}.join('<br />') %>
View the email template output. You can either use the Jenkins "Email Template Testing" feature or just run your job. You should see a whole bunch of "KEY=VALUE" print outs.
Look for the environment variable you are interested in. If your environment variable is listed in environment={BUILD_NUMBER=45, BUILD_DISPLAY_NAME=#45...}, you can just call build.environment['BUILD_NUMBER'] to get 45.
If you want to inject custom environment variables I would suggest installing the Env Inject Plugin, defining your variables through that plugin and then looking for the variable in build.envVars
It seems you can try this
template.make(build.environment)
Source
Hopefully I understood your question, but in order to read that parameter in the template you need to call it like this (if BUILD_NAME is a parameter in the jenkins job:
${ENV, var="BUILD_NAME"}
This will return the value of that parameter.
You can do something like this to get it working
<td style="color: #153643; font-family: Arial, sans-serif;font-size: 14px;padding: 20px 0px;" width="60%">
<%= build.envVars['JOB_BASE_NAME'] %>
</td>
build.envVars has all the env variables as a dictionary. Use key value pair to access the variables.
Just do:
<% def env = build.environment %>
<% def name = env.build_name %>
<% if (name != "") { %>
Name: <%=name %>
<% } %>

Resources