Outputting method result to erb - ruby

I'm working on an application that creates random sentences. I have it working as a console application, and want to make a Sinatra app which lets me display the sentences on the browser.
I have a variable #grammar that is populated from a form. I want to pass this into a method a few methods which work together to take in a string and generate a random sentence from it using a lot of logic. My rsg.erb file looks like this.
Where 'The waves portend like big yellow flowers tonight.' is the output of the expand method. I would like to display this on the erb file so it is displayed on the browser.
How can I do that?

Can you try this:
<%= #grammar %>
<%-# Assigning values to the variables in first step %>
<%-
rds = read_grammar_defs(#grammar) #get text from file and parse
sds = rds.map { |rd| split_definition rd} #use split definition to make array of strings
tgh = to_grammar_hash(sds) #create hash
rs = expand(tgh) #create sentence
%>
<%-# Printing it in second step %>
<%= rs %>

Related

Middleman Frontmatter YAML list

I just want to make a simple each loop in my Middleman helper, datas are stored in my page'Frontmatter like this :
dir:
- test
- test2
So in my helper, I try to write my loop :
def translate_directory
current_page.data.dir.each do |dir|
dir
end
end
call my method in my page
<%= translate_directory %>
and this is what's display :
["test", "test2"]
But now, if I make the same loop in my page, write with ERB syntax :
<% current_page.data.dir.each do |x| %>
<%= x %>
<% end %>
the exit is the following
test test2
separated in two strings, so exactly what I want.
EDIT : when I puts the helper'method, it display the two strings in two lines, so in two separated strings. Don't understand why it appear as an array on my browser.
EDIT 2 : a little thing I forgot, I want to translate each word with I18n.translate, like this :
def path_translate
current_page.data.dir.each { |dir| t("paths.#{dir}", locale: lang) }
end
but i can't because the each method doesn't work so I18n can't translate each word.
Because your helper is returning an array not a interpolated string like the ERB template is doing. Try the following for your helper:
def translate_directory
current_page.data.dir.join(' ')
end
My bad. Using .map instead of .each fix the problem, then use .join makes the array a big string.

How to replace words inside template placeholders

I'm trying to write a regular expression to replace <%= Name %> with "Some Person".
I'm using a regex because I want to modify it so that I don't have to worry about the spaces between = and Name as well as the E in Name and the %>
I tried:
body = %q(
Hello <%= Name %>,
This is a test. hello test
some more stuff here
and here.
<%= Name %>
)
parsed_body = body.gsub(/\A<%= Name %>\Z/, "Some person")
puts parsed_body
When parsed_body is printed out, the string is unchanged. What is wrong with my regex?
In your Regex, you have added the \A and \z anchors. These ensure that your regex only matches, if the string only contains exactly <%= Name %> with nothing before or after.
To match the your pattern anywhere in the string, you can simply remove the anchors:
parsed_body = body.gsub(/<%= Name %>/, "Some person")
Just another option considering what I am assuming you are trying to accomplish
tag_pattern = /(?<open_tag><%=\s*)(?<key>(\w+))(?<close_tag>\s*%>)/
body = <<-B
Hello,
My name is <%= Name %> and I know some things. Just because I am a
<%= Occupation %> doesn't mean I know everything, but I sure can
<%=Duty%> just as well as anyone else.
Also please don't replace <%= This %>
Thank you,
<%= Name %>
B
dict = {"Name" => "engineersmnky", "Occupation" => "Monkey", "Duty" => "drive a train"}
body.gsub(tag_pattern) {|m| dict[$2] || m }
#=> Hello,
# My name is engineersmnky and I know some things. Just because I am a
# Monkey doesn't mean I know everything, but I sure can
# drive a train just as well as anyone else.
# Also please don't replace <%= This %>
#
# Thank you,
# engineersmnky
In this case I used a dictionary of the anticipated portions of the "erb" to be replaced and used the block style of String#gsub to handle the replacements where $2 is the named capture key. When there is not a matching key it just leaves the match untouched e.g. "Also please don't replace <%= This %>"
You could implement this with any pattern you choose but if you are going to use "erb" style lines maybe try leveraging erb other wise the same will work below:
tag_pattern = (?<open_tag>{!!\s*)(?<key>(\w+))(?<close_tag>\s*!\?})
body = <<-B Hello,
My name is {!! Name !?} and I know some things. Just because I am a
{!! Occupation !?} doesn't mean I know everything, but I sure can
{!!Duty !?} just as well as anyone else.
Thank you,
{!! Name !?}
B
As long as you define tag_pattern correctly the replacement is fairly simple. Rubular Example
It looks like you're trying to write your own template parser, which is asking for a lot more trouble that it's worth considering those already exist.
However, this is the basic idea for such a thing:
erb = <<EOT
Owner: <%= name %>
Location: <%= address %>
EOT
FIELD_DATA = {
name: 'Olive Oyl',
address: '5 Sweethaven Village'
}
FIELD_RE = Regexp.union(FIELD_DATA.keys.map(&:to_s)).source # => "name|address"
puts erb.gsub(/<%=\s+(#{FIELD_RE})\s+%>/) { |k|
k # => "<%= name %>", "<%= address %>"
k[/\s+(\S+)\s+/, 1] # => "name", "address"
FIELD_DATA[k[/\s+(\S+)\s+/, 1].to_sym] # => "Olive Oyl", "5 Sweethaven Village"
}
Which, when run, outputs:
Owner: Olive Oyl
Location: 5 Sweethaven Village
This works because gsub can take a regular expression and a block. For every match of the expression it passes in the match to the block, which is then used to return the actual value being substituted in.
If you have a lot of target values, rather than use Regexp.union, instead use the RegexpTrie gem. See "Is there an efficient way to perform hundreds of text substitutions in Ruby?" for more information.
Again, template parsers exist, they've been around a long time, they're very well tested, and they handle edge cases you haven't thought about, so don't write a new partially-implemented one, instead reuse an existing one.

Rails 3.0 - Where to put this logic?

I've got a Model Task with a member due_date. I'm using Chronic to take natural language input from the user and convert it to a Time, which then gets saved to the model.
I'm just not sure the best Rails, MVC-ish way to handle these use cases:
Display a formatted string (with some logic involved) to the user every time I show Task.due_date
Allow the user to input plaintext and have it parsed automagically everywhere they can edit Task.due_date
A helper method to format time was my first idea, like this:
<%= format_time task.due_date %>
combined with an overloaded setter on an accessor in my Task model, like this:
attr_accessor :due_date_string
def due_date_string=(string)
self.due_date = Chronic.parse(string)
end
This works everywhere I want it to except in my forms for editing:
<div class="field">
<%= f.label :due_date %>
<%= f.text_field :due_date_string %>
</div>
I don't know how to make the f.text_field element 'wire up' properly so that it saves to :due_date_string, but uses the helper method to display the string.
I don't necessarily need specific code examples, just looking for the kind of pattern that pro Rails-ers would use here.
Thanks!
With according to MVC conventions, data handle is about Model layer responsibility.
So you are going in right direction to do a setter (wrapper for due_date attribute):
You need to check that is attr_acessible that is access to get a data from params
def due_date_string=(string)
self.due_date = Chronic.parse(string) || Date.today
end
The representation logic to show the parsed date is Helper layer responsibility
In order to use:
f.text_field :due_date_string
Don't you also need a getter for the new attribute? e.g.,
def due_date_string
format_time self.due_date
end
Perhaps share what error or failure occurs when you use the custom text field. :)

glue multiples text boxes into one string

I am coding a web application in ruby on rails.
I have a set of text boxes in each one there is a character and i want to glue all these text boxes in order to make one word.
The text boxes are like this :
1 %>
any ideas ??
Well for starters dont use a for loop, they ugly.
Second I wouldn't use the text_field helper rather the text_field tag
<% (1..10).each do |n| %>
<%= text_field_tag "password[#{n}]" %>
<% end %>
That will return the password all nicely chunked up

Rails 3 refactoring issue

The following view code generates a series of links with totals (as expected):
<% #jobs.group_by(&:employer_name).sort.each do |employer, jobs| %>
<%= link_to employer, jobs_path() %> <%= "(#{jobs.length})" %>
<% end %>
However, when I refactor the view's code and move the logic to a helper, the code doesn't work as expect.
view:
<%= employer_filter(#jobs_clone) %>
helper:
def employer_filter(jobs)
jobs.group_by(&:employer_name).sort.each do |employer,jobs|
link_to employer, jobs_path()
end
end
The following output is generated:
<Job:0x10342e628>#<Job:0x10342e588>#<Job:0x10342e2e0>Employer A#<Job:0x10342e1c8>Employer B#<Job:0x10342e0d8>Employer C#<Job:0x10342ded0>Employer D#
What am I not understanding? At first blush, the code seems to be equivalent.
In the first example, it is directly outputting to erb, in the second example it is returning the result of that method.
Try this:
def employer_filter(jobs)
employer_filter = ""
jobs.group_by(&:employer_name).sort.each do |employer,jobs|
employer_filter += link_to(employer, jobs_path())
end
employer_filter
end
Then call it like this in the view:
raw(employer_filter(jobs))
Also note the use of "raw". Once you move generation of a string out of the template you need to tell rails that you don't want it html escaped.
For extra credit, you could use the "inject" command instead of explicitly building the string, but I am lazy and wanted to give you what I know would work w/o testing.
This syntax worked as I hoped it would:
def employer_filter(jobs_clone)
jobs_clone.group_by(&:employer_name).sort.collect { |group,items|
link_to( group, jobs_path() ) + " (#{items.length})"
}.join(' | ').html_safe
end

Resources