rhodes-translator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rhodes_translator.rb +6 -0
- data/lib/rhodes_translator/binding.rb +86 -0
- data/lib/rhodes_translator/templates/checkbox.erb +11 -0
- data/lib/rhodes_translator/templates/content.erb +3 -0
- data/lib/rhodes_translator/templates/form.erb +6 -0
- data/lib/rhodes_translator/templates/hidden.erb +1 -0
- data/lib/rhodes_translator/templates/iuipanel.erb +8 -0
- data/lib/rhodes_translator/templates/labeledinputli.bb.erb +7 -0
- data/lib/rhodes_translator/templates/labeledinputli.erb +8 -0
- data/lib/rhodes_translator/templates/labeledrow.erb +4 -0
- data/lib/rhodes_translator/templates/labeledvalueli.bb.erb +4 -0
- data/lib/rhodes_translator/templates/labeledvalueli.erb +4 -0
- data/lib/rhodes_translator/templates/link.erb +1 -0
- data/lib/rhodes_translator/templates/link_row.erb +3 -0
- data/lib/rhodes_translator/templates/linkli.bb.erb +5 -0
- data/lib/rhodes_translator/templates/linkli.erb +6 -0
- data/lib/rhodes_translator/templates/list.bb.erb +3 -0
- data/lib/rhodes_translator/templates/list.erb +3 -0
- data/lib/rhodes_translator/templates/maplink.erb +39 -0
- data/lib/rhodes_translator/templates/panel.erb +2 -0
- data/lib/rhodes_translator/templates/password.erb +11 -0
- data/lib/rhodes_translator/templates/select.erb +14 -0
- data/lib/rhodes_translator/templates/submit.erb +4 -0
- data/lib/rhodes_translator/templates/table.erb +3 -0
- data/lib/rhodes_translator/templates/telephone.erb +1 -0
- data/lib/rhodes_translator/templates/text.erb +4 -0
- data/lib/rhodes_translator/templates/textarea.erb +10 -0
- data/lib/rhodes_translator/templates/textinput.erb +11 -0
- data/lib/rhodes_translator/templates/title.erb +3 -0
- data/lib/rhodes_translator/templates/toolbar.bb.erb +4 -0
- data/lib/rhodes_translator/templates/toolbar.erb +8 -0
- data/lib/rhodes_translator/templates/view.erb +1 -0
- data/lib/rhodes_translator/translator.rb +39 -0
- data/lib/rhodes_translator/validation.rb +99 -0
- data/spec/binding_spec.rb +169 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/stubs.rb +17 -0
- data/spec/translator_spec.rb +35 -0
- data/spec/validator_spec.rb +212 -0
- metadata +92 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
module RhodesTranslator
|
2
|
+
module Binding
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :metaorigdata
|
6
|
+
end
|
7
|
+
def bind(data,view_def,first=true)
|
8
|
+
Binding.metaorigdata = data if first
|
9
|
+
|
10
|
+
return if view_def.nil?
|
11
|
+
|
12
|
+
view_def['children'] ||= []
|
13
|
+
|
14
|
+
if view_def['repeatable'] and view_def['repeatable'] =~ /\{\{(.*?)\}\}/
|
15
|
+
pathstring = $1.strip
|
16
|
+
value = decode_path(data,pathstring)
|
17
|
+
new_children = []
|
18
|
+
repeat_def = view_def
|
19
|
+
repeat_def['repeatable'] = nil
|
20
|
+
if value.is_a? Array or value.is_a? Hash
|
21
|
+
value.each do |element|
|
22
|
+
new_def = Marshal.load(Marshal.dump(repeat_def))
|
23
|
+
new_child = self.bind(element,new_def,false)["children"]
|
24
|
+
new_child.each do |child|
|
25
|
+
new_children << child
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
view_def['children'] = new_children
|
30
|
+
else
|
31
|
+
view_def['children'].each do |child|
|
32
|
+
self.bind(data,child,false)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
view_def.each do |k,v|
|
39
|
+
unless k == 'children'
|
40
|
+
if v.is_a? String
|
41
|
+
while v =~ /\{\{(.*?)\}\}/
|
42
|
+
pathstring = $1.strip
|
43
|
+
regexp = Regexp.escape('{{' + $1 + '}}')
|
44
|
+
value = decode_path(data,pathstring)
|
45
|
+
v.gsub!(Regexp.new(regexp) , value.to_s)
|
46
|
+
end
|
47
|
+
view_def[k] = v
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
Binding.metaorigdata = nil if first
|
52
|
+
view_def
|
53
|
+
end
|
54
|
+
|
55
|
+
def decode_path(data,pathstring)
|
56
|
+
data = Binding.metaorigdata if pathstring =~ /^\//
|
57
|
+
# puts "PATH: #{pathstring}, DATA: #{data.inspect}"
|
58
|
+
elements = pathstring.split('/')
|
59
|
+
elements.delete_at(0) if pathstring =~ /^\//
|
60
|
+
# puts "ELEMENTS: #{elements.inspect}"
|
61
|
+
current = data
|
62
|
+
while element = elements.delete_at(0)
|
63
|
+
element.strip!
|
64
|
+
if current.is_a? Array
|
65
|
+
index = element.to_i
|
66
|
+
return "INVALID INDEX" if index == 0 and element[0].chr != '0'
|
67
|
+
return "INVALID INDEX" if current[index].nil?
|
68
|
+
current = current[index]
|
69
|
+
elsif current.is_a? Hash
|
70
|
+
key = element.strip
|
71
|
+
return "INVALID KEY" if current[key].nil?
|
72
|
+
current = current[key]
|
73
|
+
elsif current
|
74
|
+
begin
|
75
|
+
current = current.send element.strip
|
76
|
+
rescue Exception => e
|
77
|
+
return "INVALID DATA TYPE"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end #while
|
81
|
+
current
|
82
|
+
end #decode_path
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div <%= "class=\"#{@doc_def['div_class']}\"" if @doc_def['div_class']%> >
|
2
|
+
<label <%= "class=\"#{@doc_def['label_class']}\"" if @doc_def['label_class']%> ><%=@doc_def['label']%></label>
|
3
|
+
<input
|
4
|
+
type="checkbox"
|
5
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name'] %>
|
6
|
+
<% if @doc_def['value'] %>
|
7
|
+
<%= "checked" if @doc_def['value'] == 'true' %>
|
8
|
+
<% else %>
|
9
|
+
<%= "checked" if @doc_def['default_value'] %>
|
10
|
+
<% end %>/>
|
11
|
+
</div>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<form
|
2
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name'] %>
|
3
|
+
<%= "action=\"#{@doc_def['action']}\"" if @doc_def['action'] %>
|
4
|
+
<%= "method=\"#{@doc_def['method']}\"" if @doc_def['method'] %> >
|
5
|
+
<input type="hidden" name="metadata_action" value="<%= @action %>"/>
|
6
|
+
<%@content.each_line do |line|%><%= " " + line%><%end%></form>
|
@@ -0,0 +1 @@
|
|
1
|
+
<input type="hidden" name="<%= @doc_def["name"]%>" value="<%= @doc_def["value"] %>"/>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<li>
|
2
|
+
<label <%= "for=\"#{@doc_def['name']}\"" if @doc_def['name']%> class="fieldLabel"><%= @doc_def["label"] %></label>
|
3
|
+
<input type="text"
|
4
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name']%>
|
5
|
+
<%= "value=\"#{@doc_def['value']}\"" if @doc_def['value']%>
|
6
|
+
<%= placeholder(@doc_def["label"]) if @doc_def['label']%>
|
7
|
+
/>
|
8
|
+
</li>
|
@@ -0,0 +1 @@
|
|
1
|
+
<a href="<%= @doc_def['url'].to_s %>"><%= @doc_def['text'] %></a>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
<%
|
3
|
+
puts "MAPLINK"
|
4
|
+
if @doc_def['showmap_url']
|
5
|
+
base_url = @doc_def['showmap_url']
|
6
|
+
else
|
7
|
+
base_url = url_for :action => show_map
|
8
|
+
end
|
9
|
+
base_url = base_url + "?"
|
10
|
+
|
11
|
+
base_url = base_url + "map_type=#{@doc_def['map_type']}&" if @doc_def['map_type']
|
12
|
+
base_url = base_url + "lat=#{@doc_def['lat']}&" if @doc_def['lat']
|
13
|
+
base_url = base_url + "long=#{@doc_def['long']}&" if @doc_def['long']
|
14
|
+
base_url = base_url + "scroll=#{@doc_def['scroll']}&" if @doc_def['scroll']
|
15
|
+
base_url = base_url + "zoom=#{@doc_def['zoom']}&" if @doc_def['zoom']
|
16
|
+
base_url = base_url + "show_user=#{@doc_def['show_user']}&" if @doc_def['show_user']
|
17
|
+
base_url = base_url + "pin_location=#{@doc_def['pin_location']}&" if @doc_def['pin_location']
|
18
|
+
base_url = base_url + "title_location=#{@doc_def['title_location']}&" if @doc_def['title_location']
|
19
|
+
base_url = base_url + "subtitle_location=#{@doc_def['subtitle_location']}&" if @doc_def['subtitle_location']
|
20
|
+
base_url = base_url + "url_location=#{@doc_def['url_location']}&" if @doc_def['url_location']
|
21
|
+
base_url = base_url + "api_key=#{@doc_def['api_key']}&" if @doc_def['api_key']
|
22
|
+
base_url = base_url + "next_uri=#{@doc_def['next_uri']}&" if @doc_def['next_uri']
|
23
|
+
|
24
|
+
if @doc_def['annotations']
|
25
|
+
annotations = ""
|
26
|
+
index = 0
|
27
|
+
@doc_def['annotations'].each do |annotation|
|
28
|
+
annotation.each do |k,v|
|
29
|
+
annotations = annotations + "annotations[#{index}][#{k}]=#{v}&"
|
30
|
+
end
|
31
|
+
index = index + 1
|
32
|
+
end
|
33
|
+
base_url = base_url + annotations
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
%>
|
38
|
+
|
39
|
+
<a href="<%= base_url %>"><%= @doc_def['text'] %></a>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div <%= "class=\"#{@doc_def['div_class']}\"" if @doc_def['div_class']%> >
|
2
|
+
<label <%= "class=\"#{@doc_def['label_class']}\"" if @doc_def['label_class']%> ><%=@doc_def['label']%></label>
|
3
|
+
<input
|
4
|
+
type="password"
|
5
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name']%>
|
6
|
+
<%= "class=\"#{@doc_def['value_class']}\"" if @doc_def['value_class']%>
|
7
|
+
<%= "value=\"#{@doc_def['value']}\"" if @doc_def['value']%>
|
8
|
+
<%= "disabled" if not @doc_def['editable'].nil? and not @doc_def['editable'] %>
|
9
|
+
>
|
10
|
+
</input>
|
11
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div <%= "class=\"#{@doc_def['div_class']}\"" if @doc_def['div_class']%> >
|
2
|
+
<label <%= "class=\"#{@doc_def['label_class']}\"" if @doc_def['label_class']%> ><%=@doc_def['label']%></label>
|
3
|
+
<select
|
4
|
+
<%= "size=\"#{@doc_def['size']}\"" if @doc_def['size'] %>
|
5
|
+
<%= "class=\"#{@doc_def['class']}\"" if @doc_def['class'] %>
|
6
|
+
<%= "multiple=\"yes\"" if @doc_def['allow_multi'] %>
|
7
|
+
<%= "disabled" if not @doc_def['editable'].nil? and not @doc_def['editable'] %>
|
8
|
+
|
9
|
+
>
|
10
|
+
<% @doc_def['values'].each do |value| %>
|
11
|
+
<option <%= "selected=\"yes\"" if @doc_def['value'] == value %>><%= value %></option>
|
12
|
+
<% end %>
|
13
|
+
</select>
|
14
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= click_to_call @doc_def['number'], @doc_def['text'] %>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<div <%= "class=\"#{@doc_def['div_class']}\"" if @doc_def['div_class']%> >
|
2
|
+
<label <%= "class=\"#{@doc_def['label_class']}\"" if @doc_def['label_class']%> ><%=@doc_def['label']%></label>
|
3
|
+
<span <%= "class=\"#{@doc_def['value_class']}\"" if @doc_def['value_class']%>><%=@doc_def['value']%></span>
|
4
|
+
</div>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<textarea
|
2
|
+
type="textarea"
|
3
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name']%>
|
4
|
+
<%= "class=\"#{@doc_def['value_class']}\"" if @doc_def['value_class']%>
|
5
|
+
<%= "value=\"#{@doc_def['value']}\"" if @doc_def['value']%>
|
6
|
+
<%= "rows=\"#{@doc_def['rows']}\"" if @doc_def['rows']%>
|
7
|
+
<%= "cols=\"#{@doc_def['cols']}\"" if @doc_def['cols']%>
|
8
|
+
<%= "disabled" if not @doc_def['editable'].nil? and not @doc_def['editable'] %>
|
9
|
+
>
|
10
|
+
</textarea>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div <%= "class=\"#{@doc_def['div_class']}\"" if @doc_def['div_class']%> >
|
2
|
+
<label <%= "class=\"#{@doc_def['label_class']}\"" if @doc_def['label_class']%> ><%=@doc_def['label']%></label>
|
3
|
+
<input
|
4
|
+
type="text"
|
5
|
+
<%= "name=\"#{@doc_def['name']}\"" if @doc_def['name']%>
|
6
|
+
<%= "class=\"#{@doc_def['value_class']}\"" if @doc_def['value_class']%>
|
7
|
+
<%= "value=\"#{@doc_def['value']}\"" if @doc_def['value']%>
|
8
|
+
<%= "disabled" if not @doc_def['editable'].nil? and not @doc_def['editable'] %>
|
9
|
+
>
|
10
|
+
</input>
|
11
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div id="toolbar">
|
2
|
+
<div id="leftItem"
|
3
|
+
class="<%= @doc_def["leftclass"].nil? ? "regularButton" : @doc_def["leftclass"] %>"
|
4
|
+
><a href="<%= @doc_def["lefturi"] %>"><%= @doc_def["lefttext"] %></a></div>
|
5
|
+
<div id="rightItem"
|
6
|
+
class="<%= @doc_def["rightclass"].nil? ? "regularButton" : @doc_def["rightclass"] %>"
|
7
|
+
><a href="<%= @doc_def["righturi"] %>"><%= @doc_def["righttext"] %></a></div>
|
8
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%=@content%>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RhodesTranslator
|
2
|
+
module Translator
|
3
|
+
# Return the translated html for a
|
4
|
+
# given a view action and view definition
|
5
|
+
def translate(view_def, action='')
|
6
|
+
@content = ''
|
7
|
+
view_def['children'] ||= []
|
8
|
+
view_def['children'].each do |child|
|
9
|
+
@content += self.translate(child,action) unless child.nil?
|
10
|
+
end
|
11
|
+
load_erb(view_def,action)
|
12
|
+
end
|
13
|
+
# returns compiled erb with specified def
|
14
|
+
def load_erb(doc_def,action)
|
15
|
+
@action = action
|
16
|
+
@doc_def = doc_def
|
17
|
+
|
18
|
+
require 'rho/rhoviewhelpers'
|
19
|
+
|
20
|
+
|
21
|
+
file = File.join(Rho::RhoFSConnector.get_app_path('app'),
|
22
|
+
'templates',
|
23
|
+
"#{doc_def['type']}_erb.iseq")
|
24
|
+
|
25
|
+
|
26
|
+
file = File.join(File.dirname(File.join(__rhoGetCurrentDir(), __FILE__)),
|
27
|
+
|
28
|
+
'templates',
|
29
|
+
"#{doc_def['type']}_erb.iseq") unless File.exist? file
|
30
|
+
|
31
|
+
retval = ""
|
32
|
+
|
33
|
+
retval = eval_compiled_file(file, binding ) if File.exist? file
|
34
|
+
|
35
|
+
retval
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module RhodesTranslator
|
2
|
+
module Validation
|
3
|
+
VALIDATORS = {
|
4
|
+
'required' => '^.+$',
|
5
|
+
'number' => '[0-9]+',
|
6
|
+
'currency' => '[0-9]+\.[0-9][0-9]',
|
7
|
+
'email' => '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$',
|
8
|
+
'phone' => '^[0-9\- ]+$'
|
9
|
+
}
|
10
|
+
|
11
|
+
def validate(metadata, params)
|
12
|
+
@errors = nil
|
13
|
+
|
14
|
+
# action = metadata
|
15
|
+
#
|
16
|
+
# if action.nil?
|
17
|
+
# @errors = ["Unable to determine action"]
|
18
|
+
# return @errors
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# metadata = metadata[action] unless metadata.nil?
|
22
|
+
if metadata.nil?
|
23
|
+
@errors = ["No metadata found"]
|
24
|
+
return @errors
|
25
|
+
end
|
26
|
+
|
27
|
+
@errors = []
|
28
|
+
|
29
|
+
self.validate_data(metadata,params)
|
30
|
+
unless @errors.empty?
|
31
|
+
return @errors
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_data(metadata,params)
|
36
|
+
metadata['children'] ||= []
|
37
|
+
metadata['children'].each do |child|
|
38
|
+
self.validate_data(child,params)
|
39
|
+
end
|
40
|
+
|
41
|
+
unless metadata['validation'].nil?
|
42
|
+
if metadata['name'].nil?
|
43
|
+
@errors << "Metadata element has validation with no name"
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
if params[metadata['name']].nil?
|
48
|
+
@errors << "No value submitted for metadata element with name #{metadata['name']}"
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
value = params[metadata['name']]
|
53
|
+
|
54
|
+
|
55
|
+
return if value.to_s == "" and (metadata['validation']['validators'].nil? or not metadata['validation']['validators'].include? "required")
|
56
|
+
|
57
|
+
unless metadata['validation']['regexp'].nil?
|
58
|
+
unless value =~ Regexp.new(metadata['validation']['regexp'])
|
59
|
+
@errors << "#{metadata['label']} did not pass regexp validation"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
unless metadata['validation']['validators'].nil?
|
64
|
+
metadata['validation']['validators'].each do |validator|
|
65
|
+
unless value =~ Regexp.new(RhodesTranslator::Validation::VALIDATORS[validator])
|
66
|
+
@errors << "#{metadata['label']} did not pass validation #{validator}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
unless metadata['validation']['min_len'].nil?
|
72
|
+
if value.length < metadata['validation']['min_len'].to_i
|
73
|
+
@errors << "#{metadata['label']} too short"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
unless metadata['validation']['max_len'].nil?
|
78
|
+
if value.length > metadata['validation']['max_len'].to_i
|
79
|
+
@errors << "#{metadata['label']} too long"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
unless metadata['validation']['min_value'].nil?
|
84
|
+
if value.to_i < metadata['validation']['min_value'].to_i
|
85
|
+
@errors << "#{metadata['label']} too small"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
unless metadata['validation']['max_value'].nil?
|
90
|
+
if value.to_i > metadata['validation']['max_value'].to_i
|
91
|
+
@errors << "#{metadata['label']} too large"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
2
|
+
$:.unshift File.join(__FILE__,'..','lib')
|
3
|
+
require 'rhodes_translator'
|
4
|
+
include RhodesTranslator::Binding
|
5
|
+
describe "Binding" do
|
6
|
+
|
7
|
+
it_should_behave_like "RhodesTranslatorHelper"
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
#@b = RhodesTranslator::Binding.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should handle hashes" do
|
14
|
+
textfieldbind = { 'label' => 'Address',
|
15
|
+
'value' => '{{first_name}} {{last_name}}',
|
16
|
+
'name' => 'address1',
|
17
|
+
'type' => 'text',
|
18
|
+
'type_class' => 'show_text' }
|
19
|
+
|
20
|
+
data = {'first_name' => 'Some', 'last_name' => 'Name'}
|
21
|
+
|
22
|
+
(bind(data,textfieldbind))['value'].should == "Some Name"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should handle nested hashes" do
|
26
|
+
textfieldbind = { 'label' => 'Address',
|
27
|
+
'value' => '{{user1/first_name}} {{user1/last_name}}',
|
28
|
+
'name' => 'address1',
|
29
|
+
'type' => 'text',
|
30
|
+
'type_class' => 'show_text' }
|
31
|
+
|
32
|
+
data = {
|
33
|
+
'baduser' => {'first_name' => 'Not', 'last_name' => 'Me'},
|
34
|
+
'user1' => {'first_name' => 'Some', 'last_name' => 'Name'}
|
35
|
+
}
|
36
|
+
|
37
|
+
(bind(data,textfieldbind))['value'].should == "Some Name"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be an error for bad hash key" do
|
41
|
+
textfieldbind = { 'label' => 'Address',
|
42
|
+
'value' => '{{bad_key}}',
|
43
|
+
'name' => 'address1',
|
44
|
+
'type' => 'text',
|
45
|
+
'type_class' => 'show_text' }
|
46
|
+
|
47
|
+
data = {'first_name' => 'Some', 'last_name' => 'Name'}
|
48
|
+
|
49
|
+
(bind(data,textfieldbind))['value'].should == "INVALID KEY"
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should handle arrays" do
|
54
|
+
textfieldbind = { 'label' => 'Address',
|
55
|
+
'value' => '{{1/first_name}} {{1/last_name}}',
|
56
|
+
'name' => 'address1',
|
57
|
+
'type' => 'text',
|
58
|
+
'type_class' => 'show_text' }
|
59
|
+
|
60
|
+
data = [ {'first_name' => 'Not', 'last_name' => 'Me'},
|
61
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ]
|
62
|
+
|
63
|
+
(bind(data,textfieldbind))['value'].should == "Some Name"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should handle objects" do
|
67
|
+
textfieldbind = { 'label' => 'Address',
|
68
|
+
'value' => '{{0/first_name}} {{0/last_name}}',
|
69
|
+
'name' => 'address1',
|
70
|
+
'type' => 'text',
|
71
|
+
'type_class' => 'show_text' }
|
72
|
+
class TestObject
|
73
|
+
def first_name
|
74
|
+
'Not'
|
75
|
+
end
|
76
|
+
def last_name
|
77
|
+
'Me'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
testobj = TestObject.new
|
82
|
+
data = [ testobj ,
|
83
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ]
|
84
|
+
|
85
|
+
(bind(data,textfieldbind))['value'].should == "Not Me"
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should handle have error for object" do
|
90
|
+
textfieldbind = { 'label' => 'Address',
|
91
|
+
'value' => '{{0/first}} {{0/last_name}}',
|
92
|
+
'name' => 'address1',
|
93
|
+
'type' => 'text',
|
94
|
+
'type_class' => 'show_text' }
|
95
|
+
class TestObject
|
96
|
+
def first_name
|
97
|
+
'Not'
|
98
|
+
end
|
99
|
+
def last_name
|
100
|
+
'Me'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
testobj = TestObject.new
|
105
|
+
data = [ testobj ,
|
106
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ]
|
107
|
+
|
108
|
+
(bind(data,textfieldbind))['value'].should == "INVALID DATA TYPE Me"
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it "should be an error for a non-integer array index" do
|
114
|
+
textfieldbind = { 'label' => 'Address',
|
115
|
+
'value' => '{{user1/first_name}}',
|
116
|
+
'name' => 'address1',
|
117
|
+
'type' => 'text',
|
118
|
+
'type_class' => 'show_text' }
|
119
|
+
|
120
|
+
data = [ {'first_name' => 'Not', 'last_name' => 'Me'},
|
121
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ]
|
122
|
+
|
123
|
+
(bind(data,textfieldbind))['value'].should == "INVALID INDEX"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should be an error for invalid index" do
|
127
|
+
textfieldbind = { 'label' => 'Address',
|
128
|
+
'value' => '{{9/first_name}}',
|
129
|
+
'name' => 'address1',
|
130
|
+
'type' => 'text',
|
131
|
+
'type_class' => 'show_text' }
|
132
|
+
|
133
|
+
data = [ {'first_name' => 'Not', 'last_name' => 'Me'},
|
134
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ]
|
135
|
+
|
136
|
+
(bind(data,textfieldbind))['value'].should == "INVALID INDEX"
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
it "should expand repeatables" do
|
141
|
+
row3 = { 'label' => '{{/names/0/first_name}}',
|
142
|
+
'value' => '{{first_name}}, {{last_name}}',
|
143
|
+
'name' => 'address2',
|
144
|
+
'type' => 'labeledrow' }
|
145
|
+
|
146
|
+
|
147
|
+
table = { 'label' => 'Table',
|
148
|
+
'type' => 'table',
|
149
|
+
'children' => [ row3 ],
|
150
|
+
'repeatable' => '{{names}}' }
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
view = { 'title' => 'IUI meta panel',
|
155
|
+
'type' => 'iuipanel',
|
156
|
+
'children' => [table] }
|
157
|
+
|
158
|
+
data = {'names' => [ {'first_name' => 'Not', 'last_name' => 'Me'},
|
159
|
+
{'first_name' => 'Some', 'last_name' => 'Name'} ] }
|
160
|
+
bind(data,view)
|
161
|
+
|
162
|
+
view['children'][0]['children'][0]['label'].should == "Not"
|
163
|
+
view['children'][0]['children'][0]['value'].should == "Not, Me"
|
164
|
+
view['children'][0]['children'][1]['label'].should == "Not"
|
165
|
+
view['children'][0]['children'][1]['value'].should == "Some, Name"
|
166
|
+
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
$:.unshift File.join(__FILE__,'..','lib')
|
2
|
+
require 'rhodes_translator'
|
3
|
+
require 'stubs'
|
4
|
+
|
5
|
+
describe "RhodesTranslatorHelper", :shared => true do
|
6
|
+
before(:each) do
|
7
|
+
@textfield = { 'label' => 'Address',
|
8
|
+
'value' => '5th St.',
|
9
|
+
'name' => 'address1',
|
10
|
+
'type' => 'text',
|
11
|
+
'type_class' => 'show_text' }
|
12
|
+
|
13
|
+
|
14
|
+
@numberfield = { 'label' => 'Some Number',
|
15
|
+
'value' => 12345,
|
16
|
+
'name' => 'number1',
|
17
|
+
'type' => 'number',
|
18
|
+
'type_class' => 'show_number' }
|
19
|
+
|
20
|
+
@panel1 = { 'title' => 'Some Panel',
|
21
|
+
'type' => 'panel',
|
22
|
+
'children' => [@textfield] }
|
23
|
+
|
24
|
+
@panel2 = { 'title' => 'Some Panel',
|
25
|
+
'type' => 'panel',
|
26
|
+
'children' => [@textfield] }
|
27
|
+
@panel3 = { 'title' => 'Some Panel',
|
28
|
+
'type' => 'panel',
|
29
|
+
'children' => [@panel2] }
|
30
|
+
|
31
|
+
@view1 = { 'title' => 'View 1',
|
32
|
+
'type' => 'view',
|
33
|
+
'children' => [@panel1,@panel2] }
|
34
|
+
|
35
|
+
@view2 = { 'title' => 'View 2',
|
36
|
+
'type' => 'view',
|
37
|
+
'children' => [@view1,@view1] }
|
38
|
+
@complex = { 'title' => 'View 2',
|
39
|
+
'type' => 'view',
|
40
|
+
'children' => [@textfield,@view2,@panel3,@textfield] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_template(name)
|
44
|
+
File.join(File.dirname(__FILE__),'expected',"#{name}")
|
45
|
+
end
|
46
|
+
end
|
data/spec/stubs.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module RhodesTranslator
|
4
|
+
module Translator
|
5
|
+
|
6
|
+
def load_erb(doc_def,action)
|
7
|
+
@action = action
|
8
|
+
@doc_def = doc_def
|
9
|
+
file = File.join(File.dirname(__FILE__),
|
10
|
+
'..',
|
11
|
+
'lib',
|
12
|
+
'rhodes_translator',
|
13
|
+
'templates',"#{doc_def['type']}.erb")
|
14
|
+
ERB.new(open(file).read).result(binding)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
2
|
+
$:.unshift File.join(__FILE__,'..','lib')
|
3
|
+
require 'rhodes_translator'
|
4
|
+
include RhodesTranslator::Translator
|
5
|
+
|
6
|
+
describe "Translator" do
|
7
|
+
|
8
|
+
it_should_behave_like "RhodesTranslatorHelper"
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
# @t = RhodesTranslator::Translator.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should translate show view with nested div" do
|
15
|
+
expected = open(get_template('view_show.html')).read
|
16
|
+
translate(@view1).split.join('').should == expected.split.join('')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should translate textfield show action" do
|
20
|
+
expected = open(get_template('text_show.html')).read
|
21
|
+
translate(@textfield).should == expected
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should handle nested views" do
|
25
|
+
expected = open(get_template('nest_show.html')).read
|
26
|
+
translate(@view2).should == expected
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should handle complex templates" do
|
30
|
+
expected = open(get_template('complex_show.html')).read
|
31
|
+
translate(@complex).should == expected
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
2
|
+
$:.unshift File.join(__FILE__,'..','lib')
|
3
|
+
require 'rhodes_translator'
|
4
|
+
include RhodesTranslator::Validation
|
5
|
+
describe "Validation" do
|
6
|
+
|
7
|
+
it_should_behave_like "RhodesTranslatorHelper"
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
#@v = RhodesTranslator::Validation.new
|
11
|
+
@meta = { 'label' => 'Address',
|
12
|
+
'value' => '123 fake st',
|
13
|
+
'name' => 'address1',
|
14
|
+
'validation' => {
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should validate using custom regexp" do
|
21
|
+
|
22
|
+
@meta['validation']['regexp'] = '123 fake st'
|
23
|
+
|
24
|
+
data = {'address1' => '123 fake st'}
|
25
|
+
|
26
|
+
|
27
|
+
validate(@meta,data).should == nil
|
28
|
+
|
29
|
+
data = {'address1' => 'bad data'}
|
30
|
+
|
31
|
+
validate(@meta,data).length.should == 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have required validator" do
|
35
|
+
|
36
|
+
data = {'address1' => ''}
|
37
|
+
@meta['validation']['validators'] = ['required']
|
38
|
+
|
39
|
+
validate(@meta,data).length.should == 1
|
40
|
+
|
41
|
+
data = {'address1' => 'required'}
|
42
|
+
|
43
|
+
validate(@meta,data).should == nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have number validator" do
|
47
|
+
@meta['validation']['validators'] = ['number']
|
48
|
+
data = {'address1' => '1234'}
|
49
|
+
|
50
|
+
validate(@meta,data).should == nil
|
51
|
+
|
52
|
+
data = {'address1' => 'not a number'}
|
53
|
+
|
54
|
+
validate(@meta,data).length.should == 1
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have currency validator" do
|
59
|
+
@meta['validation']['validators'] = ['currency']
|
60
|
+
data = {'address1' => '10.00'}
|
61
|
+
|
62
|
+
validate(@meta,data).should == nil
|
63
|
+
|
64
|
+
data = {'address1' => '123'}
|
65
|
+
|
66
|
+
validate(@meta,data).length.should == 1
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have email validator" do
|
71
|
+
@meta['validation']['validators'] = ['email']
|
72
|
+
data = {'address1' => 'blah@blah.com'}
|
73
|
+
|
74
|
+
validate(@meta,data).should == nil
|
75
|
+
|
76
|
+
data = {'address1' => 'not an email'}
|
77
|
+
|
78
|
+
validate(@meta,data).length.should == 1
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should have phone validator" do
|
83
|
+
@meta['validation']['validators'] = ['phone']
|
84
|
+
data = {'address1' => '408-555-1212'}
|
85
|
+
|
86
|
+
validate(@meta,data).should == nil
|
87
|
+
|
88
|
+
data = {'address1' => 'not an phone'}
|
89
|
+
|
90
|
+
validate(@meta,data).length.should == 1
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have min_len validator" do
|
95
|
+
@meta['validation']['min_len'] = 10
|
96
|
+
data = {'address1' => '1234567890'}
|
97
|
+
|
98
|
+
validate(@meta,data).should == nil
|
99
|
+
|
100
|
+
data = {'address1' => '12345'}
|
101
|
+
|
102
|
+
validate(@meta,data).length.should == 1
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should have max_len validator" do
|
107
|
+
@meta['validation']['max_len'] = 10
|
108
|
+
data = {'address1' => '12345'}
|
109
|
+
|
110
|
+
validate(@meta,data).should == nil
|
111
|
+
|
112
|
+
data = {'address1' => '12345678901'}
|
113
|
+
|
114
|
+
validate(@meta,data).length.should == 1
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should have min_value validator" do
|
119
|
+
@meta['validation']['min_value'] = 10
|
120
|
+
data = {'address1' => '12'}
|
121
|
+
|
122
|
+
validate(@meta,data).should == nil
|
123
|
+
|
124
|
+
data = {'address1' => '2'}
|
125
|
+
|
126
|
+
validate(@meta,data).length.should == 1
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should have max_value validator" do
|
131
|
+
@meta['validation']['max_value'] = 10
|
132
|
+
data = {'address1' => '9'}
|
133
|
+
|
134
|
+
validate(@meta,data).should == nil
|
135
|
+
|
136
|
+
data = {'address1' => '11'}
|
137
|
+
|
138
|
+
validate(@meta,data).length.should == 1
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should handle multiple errors" do
|
143
|
+
@address1 = { 'label' => 'Address',
|
144
|
+
'value' => '123 fake st',
|
145
|
+
'name' => 'address1',
|
146
|
+
'validation' => {
|
147
|
+
'validators' => ['required']
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
@address2 = { 'label' => 'Address',
|
152
|
+
'value' => '123 fake st',
|
153
|
+
'name' => 'address2',
|
154
|
+
'validation' => {
|
155
|
+
'max_value' => 15,
|
156
|
+
'min_value' => 10
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
@address3 = { 'label' => 'Address',
|
161
|
+
'value' => '123 fake st',
|
162
|
+
'name' => 'address3',
|
163
|
+
'validation' => {
|
164
|
+
'max_value' => 20,
|
165
|
+
'min_value' => 12
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
@meta = { 'children' => [@address1, @address2, @address3] }
|
170
|
+
|
171
|
+
data = {'address1' => '11', 'address2' => '12', 'address3' =>'17'}
|
172
|
+
validate(@meta,data).should == nil
|
173
|
+
|
174
|
+
data = {'address1' => '', 'address2' => '12', 'address3' =>'17'}
|
175
|
+
validate(@meta,data).length.should == 1
|
176
|
+
|
177
|
+
data = {'address1' => '', 'address2' => '9', 'address3' =>'17'}
|
178
|
+
validate(@meta,data).length.should == 2
|
179
|
+
|
180
|
+
data = {'address1' => '', 'address2' => '9', 'address3' =>'22'}
|
181
|
+
validate(@meta,data).length.should == 3
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should have an error for nil metadata" do
|
186
|
+
data = {'address1' => '12'}
|
187
|
+
|
188
|
+
validate(nil,data)[0].should == "No metadata found"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should have an error for validation with no name" do
|
192
|
+
@meta = { 'label' => 'Address',
|
193
|
+
'validation' => {
|
194
|
+
'validators' => ['required']
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
data = {'address1' => '12'}
|
200
|
+
|
201
|
+
validate(@meta,data)[0].should == "Metadata element has validation with no name"
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should have an error name with no value" do
|
206
|
+
data = {'address111' => '12'}
|
207
|
+
|
208
|
+
validate(@meta,data)[0].should == "No value submitted for metadata element with name address1"
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rhodes-translator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rhomobile
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-06-07 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Extension that provides metadata capability for the Rhodes framework
|
17
|
+
email: dev@rhomobile.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/rhodes_translator.rb
|
26
|
+
- lib/rhodes_translator/binding.rb
|
27
|
+
- lib/rhodes_translator/templates/checkbox.erb
|
28
|
+
- lib/rhodes_translator/templates/content.erb
|
29
|
+
- lib/rhodes_translator/templates/form.erb
|
30
|
+
- lib/rhodes_translator/templates/hidden.erb
|
31
|
+
- lib/rhodes_translator/templates/iuipanel.erb
|
32
|
+
- lib/rhodes_translator/templates/labeledinputli.bb.erb
|
33
|
+
- lib/rhodes_translator/templates/labeledinputli.erb
|
34
|
+
- lib/rhodes_translator/templates/labeledrow.erb
|
35
|
+
- lib/rhodes_translator/templates/labeledvalueli.bb.erb
|
36
|
+
- lib/rhodes_translator/templates/labeledvalueli.erb
|
37
|
+
- lib/rhodes_translator/templates/link.erb
|
38
|
+
- lib/rhodes_translator/templates/link_row.erb
|
39
|
+
- lib/rhodes_translator/templates/linkli.bb.erb
|
40
|
+
- lib/rhodes_translator/templates/linkli.erb
|
41
|
+
- lib/rhodes_translator/templates/list.bb.erb
|
42
|
+
- lib/rhodes_translator/templates/list.erb
|
43
|
+
- lib/rhodes_translator/templates/maplink.erb
|
44
|
+
- lib/rhodes_translator/templates/panel.erb
|
45
|
+
- lib/rhodes_translator/templates/password.erb
|
46
|
+
- lib/rhodes_translator/templates/select.erb
|
47
|
+
- lib/rhodes_translator/templates/submit.erb
|
48
|
+
- lib/rhodes_translator/templates/table.erb
|
49
|
+
- lib/rhodes_translator/templates/telephone.erb
|
50
|
+
- lib/rhodes_translator/templates/text.erb
|
51
|
+
- lib/rhodes_translator/templates/textarea.erb
|
52
|
+
- lib/rhodes_translator/templates/textinput.erb
|
53
|
+
- lib/rhodes_translator/templates/title.erb
|
54
|
+
- lib/rhodes_translator/templates/toolbar.bb.erb
|
55
|
+
- lib/rhodes_translator/templates/toolbar.erb
|
56
|
+
- lib/rhodes_translator/templates/view.erb
|
57
|
+
- lib/rhodes_translator/translator.rb
|
58
|
+
- lib/rhodes_translator/validation.rb
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://rhomobile.com/
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- --charset=UTF-8
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
version:
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
version:
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.3.5
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Rhodes Metadata
|
87
|
+
test_files:
|
88
|
+
- spec/binding_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- spec/stubs.rb
|
91
|
+
- spec/translator_spec.rb
|
92
|
+
- spec/validator_spec.rb
|