How to render json with arbitrary keys using mustache? - ruby

I have a JSON object that looks like the following:
{
"XXX":{"name":"First"},
"YYY":{"name":"Second"},
....
}
I need to render it to look like:
<div>
<h1>XXX</h1>
<p>First</p>
</div>
<div>
<h1>YYY</h1>
<p>Second</p>
</div>
....
How will I accomplish this using Mustache? The problem I am facing is that I don't know how to reference the items because the key names are arbitrary.

Convert the JSON to a hash using your favorite JSON parser, that will give you something that looks like this:
json = {
"XXX" => {"name" => "First"},
"YYY" => {"name" => "Second"},
"ZZZ" => {"name" => "Third"}
}
Then simply rearrange it into a list of little hashes with known keys:
for_mustache = json.keys.inject([ ]) do |a, k|
a.push({ :k => k, :v => json[k]['name']})
a
end
There are probably cleverer ways to do that above. Now you'll have something simple and regular like this in for_mustache:
[
{ :k => "XXX", :v => "First" },
{ :k => "YYY", :v => "Second" },
{ :k => "ZZZ", :v => "Third" }
]
Then you can handle that data structure just like any other array of hashes in Mustache:
{{#for_mustache}}
<div>
<h1>{{k}}</h1>
<p>{{v}}</p>
</div>
{{/for_mustache}}

Related

In Ruby, what's the advantage of #each_pair over #each when iterating through a hash?

Let's say I want to access the values of a hash like this:
munsters = {
"Herman" => { "age" => 32, "gender" => "male" },
"Lily" => { "age" => 30, "gender" => "female" },
"Grandpa" => { "age" => 402, "gender" => "male" },
"Eddie" => { "age" => 10, "gender" => "male" },
"Marilyn" => { "age" => 23, "gender" => "female"}
}
I could use #each with two parameters:
munsters.each do |key, value|
puts "#{name} is a #{value["age"]}-year-old #{value["gender"]}."
end
Or I could use #each_pair with two parameters:
munsters.each_pair do |key, value|
puts "#{name} is a #{value["age"]}-year-old #{value["gender"]}."
end
Perhaps the difference between the two is not borne out in this simple example, but can someone help me to understand the advantage of using #each_pair over #each ?
Because Hash is an Enumerable, it has to have an each method. each_pair may be a clearer name, since it strongly suggests that two-element arrays containing key-value pairs are passed to the block.
They are aliases for each other: they share the same source code.

Convert array of key value object to object of the key values (ruby)

I have a list of objects that have key attribute and value attribute.
I would like to convert it to an object that contains attributes named as keys with the values.
Example will make it clearer...
This
[{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}]
Should become like this:
{
:key1 => "value1"
:key2 => "value2"
}
I'm sure there is one line to make it happen
Thanks
Using Hash::[], Array#map:
a = [{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}]
Hash[a.map { |h| [h[:key], h[:value]] }]
# => {"key1"=>"value1", "key2"=>"value2"}
Hash[a.map { |h| h.values_at(:key, :value) }]
# => {"key1"=>"value1", "key2"=>"value2"}
Hash[a.map { |h| [h[:key].to_sym, h[:value]] }]
# => {:key1=>"value1", :key2=>"value2"}
a.each_with_object({}) {|h,g| g.update({h[:key].to_sym => h[:value]}) }
# => {:key1=>"value1", :key2=>"value2"}
Hash[array.map(&:values)]
#=> {"key1"=>"value1", "key2"=>"value2"}
Just to promote the to_h a bit:
[{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}].map(&:values).map{|k,v| [k.to_sym,v]}.to_h
# => {:key1=>"value1", :key2=>"value2"}

Parse Array hashes in new object with ruby

I am struggling with some arrays with hashes inside. I want to parse them into a new object but have no idea how to do this.
Here is the data:
[
{
"name" => "itemHref",
"value" => "https://192.168.75.145:8281/api/workflows/16da1fa1-7c8b-4602-8d53-17fc5e1fa3ff/"
},
{
"name" => "id",
"value" => "16da1fa1-7c8b-4602-8d53-17fc5e1fa3ff"
},
{
"name" => "categoryName",
"value" => "FinanzInformatik"
},
{
"name" => "canExecute",
"value" => "true"
},
{
"name" => "categoryHref",
"value" => "https://192.168.75.145:8281/api/catalog/System/WorkflowCategory/ff8080813b90a145013b90cac51b0006/"
},
{
"name" => "description",
"value" => "bekommt alle VMs"
},
{
"name" => "name",
"value" => "getAllVms"
},
{
"name" => "type",
"value" => "Workflow"
},
{
"name" => "canEdit",
"value" => "true"
}
]
And, here is my code:
require 'rest-client'
require 'json'
class Workflow
def initialize(itemHref, id, categoryName, canExecute, categoryHref, description, name, type, canEdit)
#itemHref = itemHref
#id = id
#categoryName = categoryName
#canExecute = canExecute
#categoryHref = categoryHref
#description = description
#name = name
#type = type
#canEdit = canEdit
end
end
json_string = RestClient.get( "http://vcoadmin:vcoadmin#192.168.75.145:8280/api/workflows", :content_type => 'application/json', :accept => 'application/json')
parsed = JSON.parse(json_string)
parsed.each do |a, b|
if(b.class == Array)
b.flatten.each do |c|
p c['attributes']
#c['attributes'].each
{
|f| p f['name'], f['value'] }
end
end
end
How do I put the hash value into the object? I think about something based on the 'name' which is the identifier for the value.
Any ideas?
Assuming that the order of attributes shouldn't be changed:
Workflow.new(*parsed.map {|attr| attr['value']})
I would implement a PORO that can be initialized with a hash. So then you are able to pass your hash directly in to creating the workflow.
An example of this is can be seen: http://pullmonkey.com/2008/01/06/convert-a-ruby-hash-into-a-class-object/

Ruby nested hash syntax & structure

I'm building a tree of html elements, class names and their counts.
How would I structure this code with the proper syntax?
$html = {
:p => [
{ 'quote' => 10 },
{ 'important' => 4 }
],
:h2 => [
{ 'title' => 33 },
{ 'subtitle' => 15 }
]
}
I'm confused by the nested hash syntax. Thanks for the help setting me straight.
A simple way to structure a HTML tree could be:
html = [
{ _tag: :p, quote: 10, important: 4 },
{ _tag: :h2, title: 33, subtitle: 15 },
]
Where html[0][:_tag] is the tag name, and other attributes are accessible through html[0][attr]. The root element is an array since multiple elements of the same type (multiple paragraphs) could exist in the same namespace and a hash would only store the last added one.
A more advanced example which would allow nested contents:
tree = { _tag: :html, _contents: [
{ _tag: :head, _contents: [
{ _tag: :title, _contents: "The page title" },
]},
{ _tag: :body, id: 'body-id', _contents: [
{ _tag: :a, href: 'http://google.com', id: 'google-link', _contents: "A link" },
]},
]}
After defining the HTML element you don't assign another hash, but a list and from your question title I guess you want to nest another hash directly. Thus you do not start with a square bracket, but with another curly brace:
$html = {
:p => { 'quote' => 10, 'important' => 4 },
:h2 => { 'title' => 33, 'subtitle' => 15 }
}
#Example
puts $html[:p]['quote']
Which will print:
10
Take a look at the constructor documentation of Hash, there are different ways to initialize hashes, maybe you find a more intuitive one.

Comparing value of array in Mustache block loop

So I am trying to render a select drop-down from an array using Mustache and Sinatra. The template code currently looks like this:
<select id="phone_prefix" name="phone_prefix">
{{#prefixes}}
<option value="{{to_s}}" {{selected}}>{{to_s}}</option>
{{/prefixes}}
</select>
With the following method in the view it is rendering each item of the array:
def prefixes
["03", "04", "06", "07", "09", "021", "022", "025", "027", "028", "029"]
end
For the {{selected}} value in the mustache template I need to do a comparison on the array item currently being iterated over and a query string value coming in via params[:phone_prefix] which for instance is "09". Then when there is a match return a value of "selected" to a selected method to pass to mustache.
Any help would be greatly appreciated.
Push the logic into your Ruby and just feed data to Mustache. Update your prefixes method to return an Array of Hashes:
def prefixes
# figure out which one is selected by asking params...
[ { :n => '03', :selected => false }, { :n => '04', :selected => true }, ... ]
end
and then something like this in your template:
<select id="phone_prefix" name="phone_prefix">
{{#prefixes}}
<option value="{{n}}" {{#selected}}selected="selected"{{/selected}}>{{n}}</option>
{{/prefixes}}
</select>
I've only used Mustache in JavaScript so I might be missing something in the Ruby flavor but something close to that should work, you just have to get information from params into your prefixes method.
Mustache is intentionally minimalistic and free of logic, it even says so on the homepage:
Logic-less templates.
So all your logic goes in your code and you just set a bunch of variables and flags for Mustache to do things with. The only logic available in the template is "is this thing true?" and "can I iterate over this thing?"; anything more complicated than that has to go in the code that is preparing data for Mustache.
Rad! Thanks! That worked a treat. I ended up with the following method for prefixes and it works great:
def prefixes
prefix_list = [{:n => "03", :selected => false}, {:n => "04", :selected => false}, {:n => "06", :selected => false}, {:n => "07", :selected => false}, {:n => "09", :selected => false}, {:n => "021", :selected => false}, {:n => "022", :selected => false}, {:n => "025", :selected => false}, {:n => "027", :selected => false}, {:n => "028", :selected => false}, {:n => "029", :selected => false}]
prefix_list.each do |i|
if i[:n] == "09"
i[:selected] = true
end
end
prefix_list
end

Resources