dolores-cfml 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +6 -3
- data/VERSION +1 -1
- data/cfml.gemspec +16 -13
- data/lib/cfml/converters/jsawesome.rb +92 -0
- data/lib/cfml/parser.rb +52 -12
- data/lib/cfml/tag.rb +31 -4
- data/lib/cfml/tags/checkbox.rb +7 -4
- data/lib/cfml/tags/checkboxes.rb +3 -3
- data/lib/cfml/tags/group.rb +4 -0
- data/lib/cfml/tags/option.rb +25 -0
- data/lib/cfml/tags/radio.rb +6 -3
- data/lib/cfml/tags/radios.rb +3 -3
- data/lib/cfml/tags/select.rb +8 -1
- data/lib/cfml/tags/unknown.rb +4 -0
- data/spec/complex_spec.rb +1 -1
- data/spec/converters/jsawesome_spec.rb +55 -0
- data/spec/fixtures/complex.cfml +5 -6
- data/spec/fixtures/invalid.cfml +10 -0
- data/spec/{gold_spec.rb → meta_spec.rb} +12 -4
- data/spec/tags/checkbox_spec.rb +17 -0
- data/spec/tags/checkboxes_spec.rb +5 -1
- data/spec/tags/select_spec.rb +27 -3
- data/spec/tags/text_spec.rb +1 -1
- data/spec/validation_spec.rb +19 -0
- metadata +12 -9
- data/spec/tags/radio_spec.rb +0 -18
- data/spec/tags/radios_spec.rb +0 -26
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
gem.authors = ["Chris Van Pelt"]
|
13
13
|
gem.add_dependency 'liquid', '>= 2.0.0'
|
14
14
|
gem.add_dependency 'nokogiri', '>= 1.3.3'
|
15
|
-
gem.add_dependency '
|
15
|
+
gem.add_dependency 'json_pure', '>= 1.1.3'
|
16
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
17
|
end
|
18
18
|
|
@@ -32,8 +32,11 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
32
32
|
spec.rcov = true
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
task :refresh_builder => [:build] do
|
36
|
+
cp "pkg/cfml-#{File.read("VERSION").strip}.gem", "../builder/gems/cache/"
|
37
|
+
rm_rf "../builder/gems/gems/cfml-#{File.read("VERSION").strip}/"
|
38
|
+
`cd ../builder && bin/thor merb:gem:redeploy`
|
39
|
+
end
|
37
40
|
|
38
41
|
task :default => :spec
|
39
42
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/cfml.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{cfml}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Chris Van Pelt"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-19}
|
10
10
|
s.description = %q{CFML let's you easily create form elements and custom interfaces for the CrowdFlower CroudSourcing platform}
|
11
11
|
s.email = %q{vanpelt@doloreslabs.com}
|
12
12
|
s.extra_rdoc_files = [
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
"VERSION",
|
23
23
|
"cfml.gemspec",
|
24
24
|
"lib/cfml.rb",
|
25
|
+
"lib/cfml/converters/jsawesome.rb",
|
25
26
|
"lib/cfml/liquid_filters.rb",
|
26
27
|
"lib/cfml/parser.rb",
|
27
28
|
"lib/cfml/tag.rb",
|
@@ -29,6 +30,7 @@ Gem::Specification.new do |s|
|
|
29
30
|
"lib/cfml/tags/checkboxes.rb",
|
30
31
|
"lib/cfml/tags/group.rb",
|
31
32
|
"lib/cfml/tags/hidden.rb",
|
33
|
+
"lib/cfml/tags/option.rb",
|
32
34
|
"lib/cfml/tags/radio.rb",
|
33
35
|
"lib/cfml/tags/radios.rb",
|
34
36
|
"lib/cfml/tags/ratings.rb",
|
@@ -37,20 +39,21 @@ Gem::Specification.new do |s|
|
|
37
39
|
"lib/cfml/tags/textarea.rb",
|
38
40
|
"lib/cfml/tags/unknown.rb",
|
39
41
|
"spec/complex_spec.rb",
|
42
|
+
"spec/converters/jsawesome_spec.rb",
|
40
43
|
"spec/fixtures/complex.cfml",
|
41
|
-
"spec/
|
44
|
+
"spec/fixtures/invalid.cfml",
|
45
|
+
"spec/meta_spec.rb",
|
42
46
|
"spec/sorta_match.rb",
|
43
47
|
"spec/spec_helper.rb",
|
44
48
|
"spec/tags/checkbox_spec.rb",
|
45
49
|
"spec/tags/checkboxes_spec.rb",
|
46
50
|
"spec/tags/group_spec.rb",
|
47
51
|
"spec/tags/hidden_spec.rb",
|
48
|
-
"spec/tags/radio_spec.rb",
|
49
|
-
"spec/tags/radios_spec.rb",
|
50
52
|
"spec/tags/select_spec.rb",
|
51
53
|
"spec/tags/text_spec.rb",
|
52
54
|
"spec/tags/textarea_spec.rb",
|
53
|
-
"spec/tags/unknown_spec.rb"
|
55
|
+
"spec/tags/unknown_spec.rb",
|
56
|
+
"spec/validation_spec.rb"
|
54
57
|
]
|
55
58
|
s.homepage = %q{http://github.com/dolores/cfml}
|
56
59
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -59,19 +62,19 @@ Gem::Specification.new do |s|
|
|
59
62
|
s.summary = %q{CFML is Crowd Flower Markup Language}
|
60
63
|
s.test_files = [
|
61
64
|
"spec/complex_spec.rb",
|
62
|
-
"spec/
|
65
|
+
"spec/converters/jsawesome_spec.rb",
|
66
|
+
"spec/meta_spec.rb",
|
63
67
|
"spec/sorta_match.rb",
|
64
68
|
"spec/spec_helper.rb",
|
65
69
|
"spec/tags/checkbox_spec.rb",
|
66
70
|
"spec/tags/checkboxes_spec.rb",
|
67
71
|
"spec/tags/group_spec.rb",
|
68
72
|
"spec/tags/hidden_spec.rb",
|
69
|
-
"spec/tags/radio_spec.rb",
|
70
|
-
"spec/tags/radios_spec.rb",
|
71
73
|
"spec/tags/select_spec.rb",
|
72
74
|
"spec/tags/text_spec.rb",
|
73
75
|
"spec/tags/textarea_spec.rb",
|
74
|
-
"spec/tags/unknown_spec.rb"
|
76
|
+
"spec/tags/unknown_spec.rb",
|
77
|
+
"spec/validation_spec.rb"
|
75
78
|
]
|
76
79
|
|
77
80
|
if s.respond_to? :specification_version then
|
@@ -81,15 +84,15 @@ Gem::Specification.new do |s|
|
|
81
84
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
82
85
|
s.add_runtime_dependency(%q<liquid>, [">= 2.0.0"])
|
83
86
|
s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.3"])
|
84
|
-
s.add_runtime_dependency(%q<
|
87
|
+
s.add_runtime_dependency(%q<json_pure>, [">= 1.1.3"])
|
85
88
|
else
|
86
89
|
s.add_dependency(%q<liquid>, [">= 2.0.0"])
|
87
90
|
s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
|
88
|
-
s.add_dependency(%q<
|
91
|
+
s.add_dependency(%q<json_pure>, [">= 1.1.3"])
|
89
92
|
end
|
90
93
|
else
|
91
94
|
s.add_dependency(%q<liquid>, [">= 2.0.0"])
|
92
95
|
s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
|
93
|
-
s.add_dependency(%q<
|
96
|
+
s.add_dependency(%q<json_pure>, [">= 1.1.3"])
|
94
97
|
end
|
95
98
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module CFML
|
2
|
+
module Converters
|
3
|
+
class JSAwesome
|
4
|
+
def initialize(json)
|
5
|
+
parsed = JSON.parse(json)
|
6
|
+
@json = parsed[0] || []
|
7
|
+
@labels = parsed[1] || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def convert
|
11
|
+
@json.map do |k,v|
|
12
|
+
if k.is_a?(Array)
|
13
|
+
(k << v).map {|k,v| process(k,v)}
|
14
|
+
else
|
15
|
+
process(k,v)
|
16
|
+
end
|
17
|
+
end.join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def label(k)
|
21
|
+
k = k.sub(/^[_#*^~]?\+?/,'')
|
22
|
+
l = @labels[k]
|
23
|
+
label = l.is_a?(Hash) ? l["label"] : l if l
|
24
|
+
label ||= k.capitalize.gsub(/_/,' ')
|
25
|
+
end
|
26
|
+
|
27
|
+
def tag(tag, val, opts = {})
|
28
|
+
val = Array(val)
|
29
|
+
parts = val[0].split("|")
|
30
|
+
key = parts[0].sub(/^[_#*^~]?\+?/,'')
|
31
|
+
attrs = ["label=\"#{label(parts[0])}\""]
|
32
|
+
attrs << "name=\"#{parts[1]}\"" if parts[1]
|
33
|
+
attrs << "checked=\"true\"" if val[1]
|
34
|
+
attrs << "required=\"true\"" if @labels[key] && @labels[key]["required"]
|
35
|
+
opts.reject {|k,v| v.to_s.strip.length == 0}.each do |k,v|
|
36
|
+
attrs << "#{k}=\"#{v}\""
|
37
|
+
end
|
38
|
+
if @labels["gold"] && @labels["gold"][key]
|
39
|
+
src = @labels["gold"][key]
|
40
|
+
gattrs = ["src=\"#{src}\""]
|
41
|
+
regex = Array(@labels["gold"]["_"+src+"_regex"])
|
42
|
+
gattrs << "regex=\"#{regex[0]}\"" if regex[0]
|
43
|
+
gattrs << "flags=\"#{regex[1]}\"" if regex[1]
|
44
|
+
gattrs << "strict=\"true\"" if @labels["gold"]["_"+src+"_strict"]
|
45
|
+
gold = "><cf:gold #{gattrs.join(" ")} /></cf:#{tag}>"
|
46
|
+
else
|
47
|
+
gold = "/>"
|
48
|
+
end
|
49
|
+
|
50
|
+
"<cf:#{tag} #{attrs.join(" ")} #{gold}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def process(k,v)
|
54
|
+
select_default = @labels['{}'] || "Choose Category"
|
55
|
+
cfml = case v
|
56
|
+
#a select tag or group of radios/checkboxes
|
57
|
+
when Array:
|
58
|
+
if(k =~ /^[^_]/)
|
59
|
+
if $~[0] == "*"
|
60
|
+
parent = "radios"
|
61
|
+
child = "radio"
|
62
|
+
elsif $~[0] == "^"
|
63
|
+
parent = "checkboxes"
|
64
|
+
child = "checkbox"
|
65
|
+
else
|
66
|
+
parent = "select"
|
67
|
+
child = "option"
|
68
|
+
end
|
69
|
+
<<-HTML
|
70
|
+
<cf:#{parent} label="#{label(k)}">
|
71
|
+
#{v.map { |c| tag(child, c)}.join("\n")}
|
72
|
+
</cf:#{parent}>
|
73
|
+
HTML
|
74
|
+
#Multiple hidden fields...
|
75
|
+
elsif(k =~ /^_/)
|
76
|
+
v.map { |c| tag("hidden", c)}.join("\n")
|
77
|
+
end
|
78
|
+
else
|
79
|
+
if(k =~ /^#/)
|
80
|
+
tag("textarea", k, {:default => v})
|
81
|
+
elsif(k =~ /^_/)
|
82
|
+
tag("hidden", k, {:value => v})
|
83
|
+
elsif(k =~ /^\^/)
|
84
|
+
tag("checkbox", k, {:default => v})
|
85
|
+
else
|
86
|
+
tag("text", k, {:default => v})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/cfml/parser.rb
CHANGED
@@ -1,37 +1,77 @@
|
|
1
1
|
module CFML
|
2
2
|
class Parser
|
3
|
+
attr_reader :doc, :cftags, :tags, :errors
|
4
|
+
|
3
5
|
def initialize(content, opts = {})
|
4
6
|
@opts = opts
|
5
|
-
@doc =
|
7
|
+
@doc = Parser.parse(content)
|
6
8
|
@cftags = @doc.xpath("//cf:*[not(ancestor::cf:*)]")
|
9
|
+
@tags = @cftags.map do |t|
|
10
|
+
tag_class(t.name).new(t, @opts)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse(content)
|
15
|
+
Nokogiri::XML("<root xmlns:cf='http://crowdflower.com'>#{content}</root>")
|
7
16
|
end
|
8
17
|
|
9
18
|
def convert
|
10
|
-
@cftags.
|
11
|
-
t.replace(
|
19
|
+
@cftags.each_with_index do |t,i|
|
20
|
+
t.replace(@tags[i].convert)
|
12
21
|
end
|
13
22
|
@doc
|
14
23
|
end
|
15
24
|
|
25
|
+
def fields
|
26
|
+
@fields = {}
|
27
|
+
@tags.each do |g|
|
28
|
+
agg = g.attrs["aggregation"]
|
29
|
+
@fields[g.name] = agg.to_s if agg
|
30
|
+
end
|
31
|
+
@fields
|
32
|
+
end
|
33
|
+
|
16
34
|
def golds
|
17
35
|
return @golds if @golds
|
18
36
|
@golds = {}
|
19
|
-
@
|
20
|
-
|
21
|
-
next unless
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
@golds[ref] = gold
|
37
|
+
@tags.each do |g|
|
38
|
+
gold = g.gold?
|
39
|
+
next unless gold
|
40
|
+
val = (gold.attributes["gold"] || gold.attributes["src"]).to_s
|
41
|
+
val = "#{g.name}_gold" if val =~ /^(true|\s*)$/
|
42
|
+
@golds[g.name] = val
|
26
43
|
["strict","regex"].each do |attrs|
|
27
|
-
if a =
|
28
|
-
@golds["_#{
|
44
|
+
if a = gold.attributes[attrs]
|
45
|
+
@golds["_#{val}_#{attrs}"] = attrs == "regex" ? [a.to_s, gold.attributes["flags"].to_s] : a.to_s
|
29
46
|
end
|
30
47
|
end
|
31
48
|
end
|
32
49
|
@golds
|
33
50
|
end
|
34
51
|
|
52
|
+
def valid?
|
53
|
+
@errors = []
|
54
|
+
@tags.select {|t| t.validate? && t.name =~ /^\s*$/ }.each do |t|
|
55
|
+
@errors << [t.to_s.split("\n")[0], "does not have a label or name specified."]
|
56
|
+
end
|
57
|
+
dupes = @tags.select do |tag|
|
58
|
+
tag.validate? && @tags.select {|t| t.name == tag.name}.length > 1
|
59
|
+
end
|
60
|
+
(dupes[1..-1] || []).each do |t|
|
61
|
+
@errors << [t.to_s.split("\n")[0], "has a duplicated name, please specify a unique name attribute."]
|
62
|
+
end
|
63
|
+
@tags.each do |t|
|
64
|
+
next unless t.children
|
65
|
+
dupes = t.children.select do |child|
|
66
|
+
t.children.select {|c| c.value == child.value}.length > 1
|
67
|
+
end
|
68
|
+
(dupes[1..-1] || []).each do |c|
|
69
|
+
@errors << [c.to_s, "a child of #{t.to_s.split("\n")[0]} has a duplicated value, please specify a unique value attribute."]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
@errors.length == 0
|
73
|
+
end
|
74
|
+
|
35
75
|
def wrap(content)
|
36
76
|
@opts[:no_wrap] ? content : "<div class=\"cfml #{@opts[:prefix]}\">#{content}</div>"
|
37
77
|
end
|
data/lib/cfml/tag.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module CFML
|
2
2
|
class Tag
|
3
|
+
attr_reader :attrs, :tag, :data
|
4
|
+
|
3
5
|
def initialize(cfml, opts = {})
|
4
|
-
@cfml = cfml
|
6
|
+
@cfml = cfml.is_a?(String) ? Parser.parse(cfml).root.children.first : cfml
|
5
7
|
@attrs = @cfml.attributes#Hash[*cfml.attributes.map {|k,v| [k.intern,v]}.flatten]
|
6
8
|
@tag = @cfml.name
|
7
9
|
@opts = opts
|
@@ -11,6 +13,10 @@ module CFML
|
|
11
13
|
@opts[:prefix] ? "#{@opts[:prefix]}[#{name}]" : "#{name}"
|
12
14
|
end
|
13
15
|
|
16
|
+
def gold?
|
17
|
+
@attrs["gold"] ? @cfml : @cfml.at("./cf:gold")
|
18
|
+
end
|
19
|
+
|
14
20
|
def name
|
15
21
|
(@attrs["name"] || @attrs["label"]).to_s.downcase.gsub(/\s/,"_").gsub(/\W/,"")
|
16
22
|
end
|
@@ -20,6 +26,10 @@ module CFML
|
|
20
26
|
"#{@tag} #{extras}".strip
|
21
27
|
end
|
22
28
|
|
29
|
+
def children
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
23
33
|
def classes
|
24
34
|
@classes ||= [name] << validations << @attrs["class"].to_s.split(/ /)
|
25
35
|
@classes.uniq.reject {|c| c.length == 0 }.join(" ").strip
|
@@ -34,24 +44,37 @@ module CFML
|
|
34
44
|
wrapper(@parsed)
|
35
45
|
end
|
36
46
|
|
47
|
+
def to_s
|
48
|
+
@cfml.to_s
|
49
|
+
end
|
50
|
+
|
37
51
|
def label(label, tag = "label")
|
52
|
+
label ||= @attrs["name"].to_s.capitalize
|
38
53
|
required = " <span class=\"required\">(required)</span>" if validations.include?("required")
|
39
|
-
"<#{tag}>#{label}#{required}</#{tag}>" if label
|
54
|
+
"<#{tag}>#{label}#{required}</#{tag}>" if label.to_s != ""
|
40
55
|
end
|
41
56
|
|
42
57
|
def legend(label)
|
43
58
|
label(label, "legend") if label
|
44
59
|
end
|
45
60
|
|
61
|
+
def to_liquid
|
62
|
+
to_html
|
63
|
+
end
|
64
|
+
|
46
65
|
def validations
|
47
66
|
@validations ||= @attrs["validations"].to_s.split(/ /).map {|v| "validates-#{v}"}
|
48
67
|
end
|
49
68
|
|
50
69
|
def instructions
|
51
|
-
@instructions ||= @attrs["instructions"] || (@cfml.at("instructions") ? @cfml.at("instructions").inner_html : nil)
|
70
|
+
@instructions ||= @attrs["instructions"] || (@cfml.at("./cf:instructions") ? @cfml.at("./cf:instructions").inner_html : nil)
|
52
71
|
@instructions ? "<p class=\"instructions\">#{@instructions}</p>" : nil
|
53
72
|
end
|
54
73
|
|
74
|
+
def validate?
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
55
78
|
def wrapper(parsed, tag = "div")
|
56
79
|
#Deal with a label only wrapper... kinda jank
|
57
80
|
if tag == "label" && instructions
|
@@ -62,13 +85,17 @@ module CFML
|
|
62
85
|
"<#{tag} class=\"#{wrapper_classes}\">#{parsed}#{instructions}</#{tag}>"
|
63
86
|
end
|
64
87
|
|
88
|
+
def value
|
89
|
+
@attrs["value"].to_s
|
90
|
+
end
|
91
|
+
|
65
92
|
def data
|
66
93
|
(@opts[:data] || {}).merge({
|
67
94
|
"name" => prefix(name),
|
68
95
|
"label" => label(@attrs["label"]),
|
69
96
|
"legend" => legend(@attrs["label"]),
|
70
97
|
"classes" => classes,
|
71
|
-
"value" =>
|
98
|
+
"value" => value
|
72
99
|
})
|
73
100
|
end
|
74
101
|
end
|
data/lib/cfml/tags/checkbox.rb
CHANGED
@@ -3,7 +3,7 @@ module CFML
|
|
3
3
|
class Checkbox < Tag
|
4
4
|
Template = <<-HTML.freeze
|
5
5
|
{{default}}
|
6
|
-
<label><input name="{{name}}" type="checkbox" value="{{value}}" class="{{classes}}"/> {{label}}</label>
|
6
|
+
<label><input name="{{name}}" type="checkbox" value="{{value}}" class="{{classes}}" {{checked}}/> {{label}}</label>
|
7
7
|
HTML
|
8
8
|
|
9
9
|
def prefix(name)
|
@@ -21,10 +21,13 @@ module CFML
|
|
21
21
|
def data
|
22
22
|
default = ""
|
23
23
|
if @attrs["default"]
|
24
|
-
default =
|
24
|
+
default = Hidden.new("<cf:hidden name=\"#{name}\" value=\"#{@attrs["default"]}\"/>", @opts).to_html
|
25
25
|
end
|
26
|
-
|
27
|
-
|
26
|
+
super.merge({
|
27
|
+
"value" => (@attrs["value"] || (grouped? ? @attrs["label"] : "true")).to_s,
|
28
|
+
"default" => default,
|
29
|
+
"checked" => @attrs["checked"] ? "checked=\"checked\"" : "",
|
30
|
+
"label" => @attrs["label"].to_s})
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
data/lib/cfml/tags/checkboxes.rb
CHANGED
@@ -9,14 +9,14 @@ module CFML
|
|
9
9
|
HTML
|
10
10
|
|
11
11
|
def data
|
12
|
-
super.merge({"checkboxes" =>
|
12
|
+
super.merge({"checkboxes" => children})
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def children
|
16
16
|
@cfml.xpath("cf:checkbox").map do |c|
|
17
17
|
c["name"] ||= name
|
18
18
|
c["validations"] ||= @attrs["validations"].to_s
|
19
|
-
Checkbox.new(c, @opts)
|
19
|
+
Checkbox.new(c, @opts)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
data/lib/cfml/tags/group.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module CFML
|
2
|
+
module Tags
|
3
|
+
class Option < Tag
|
4
|
+
Template = <<-HTML.freeze
|
5
|
+
<option {{value}} {{selected}}>{{label}}</option>
|
6
|
+
HTML
|
7
|
+
|
8
|
+
def wrapper(parsed)
|
9
|
+
parsed
|
10
|
+
end
|
11
|
+
|
12
|
+
def value
|
13
|
+
(@attrs["value"] || @attrs["label"]).to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def data
|
17
|
+
super.merge({
|
18
|
+
"value" => @attrs["value"] ? "value=\"#{@attrs["value"]}\"" : "",
|
19
|
+
"selected" => @attrs["selected"] ? "selected=\"selected\"" : "",
|
20
|
+
"label" => (@attrs["label"] || @cfml.inner_html).to_s
|
21
|
+
})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/cfml/tags/radio.rb
CHANGED
@@ -2,7 +2,7 @@ module CFML
|
|
2
2
|
module Tags
|
3
3
|
class Radio < Tag
|
4
4
|
Template = <<-HTML.freeze
|
5
|
-
<label><input name="{{name}}" type="radio" value="{{value}}" class="{{classes}}"/> {{label}}</label>
|
5
|
+
<label><input name="{{name}}" type="radio" value="{{value}}" class="{{classes}}" {{checked}}/> {{label}}</label>
|
6
6
|
HTML
|
7
7
|
|
8
8
|
#Radios should always be grouped, but for consistency with checkboxes, we check
|
@@ -15,8 +15,11 @@ module CFML
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def data
|
18
|
-
|
19
|
-
|
18
|
+
super.merge({
|
19
|
+
"value" => (@attrs["value"] || @attrs["label"]).to_s,
|
20
|
+
"checked" => @attrs["checked"] ? "checked=\"checked\"" : "",
|
21
|
+
"label" => @attrs["label"].to_s
|
22
|
+
})
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
data/lib/cfml/tags/radios.rb
CHANGED
@@ -9,14 +9,14 @@ module CFML
|
|
9
9
|
HTML
|
10
10
|
|
11
11
|
def data
|
12
|
-
super.merge({"radios" =>
|
12
|
+
super.merge({"radios" => children})
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def children
|
16
16
|
@cfml.xpath("cf:radio").map do |c|
|
17
17
|
c["name"] ||= name
|
18
18
|
c["validations"] ||= @attrs["validations"].to_s
|
19
|
-
Radio.new(c, @opts)
|
19
|
+
Radio.new(c, @opts)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
data/lib/cfml/tags/select.rb
CHANGED
@@ -8,8 +8,15 @@ module CFML
|
|
8
8
|
</select>
|
9
9
|
HTML
|
10
10
|
|
11
|
+
def children
|
12
|
+
default = @cfml["default"] ? [Option.new("<cf:option value=\"\">#{@cfml["default"]}</cf:option>", @opts)] : []
|
13
|
+
default + @cfml.xpath("cf:option").map do |c|
|
14
|
+
Option.new(c, @opts)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
11
18
|
def data
|
12
|
-
super.merge({"options" =>
|
19
|
+
super.merge({"options" => children})
|
13
20
|
end
|
14
21
|
end
|
15
22
|
end
|
data/lib/cfml/tags/unknown.rb
CHANGED
data/spec/complex_spec.rb
CHANGED
@@ -43,7 +43,7 @@ describe "CFML Complex" do
|
|
43
43
|
<label>
|
44
44
|
<input name="u12345[rad][]" class="rad" type="checkbox" value="Sure?">
|
45
45
|
Sure?</label>
|
46
|
-
|
46
|
+
<p class=\"instructions\">This <i>is</i> cool</p>
|
47
47
|
</fieldset>
|
48
48
|
<input type="hidden" name="u12345[secret]" value="cool" class="secret" />
|
49
49
|
</div>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/cfml/converters/jsawesome")
|
3
|
+
|
4
|
+
describe "JSAwesome Converter" do
|
5
|
+
it "converts" do
|
6
|
+
json = "[[
|
7
|
+
[\"text_field\", \"default value\"],
|
8
|
+
[\"#text_area\", \"\"],
|
9
|
+
[\"single_select\", [\"boo\", \"~yah\"]],
|
10
|
+
[\"^check\", [\"One|totally_rad\", [\"two\",true], \"three\"]],
|
11
|
+
[\"*radio\", [\"a\", \"b\", [\"c\", true]]],
|
12
|
+
[\"_hidden\",\"hot\"],
|
13
|
+
[[\"^single_check\"],[\"^Edge|edge_case\", false]]
|
14
|
+
],
|
15
|
+
{\"text_field\": \"JSAwesome\",
|
16
|
+
\"text_area\": {
|
17
|
+
\"required\":true,
|
18
|
+
\"validation\": [\"\\d+\", \"Field must contain atleast one digit\"],
|
19
|
+
\"label\": \"Input some text with atleast one digit\"
|
20
|
+
},
|
21
|
+
\"single_select\": {
|
22
|
+
\"required\":true
|
23
|
+
},
|
24
|
+
\"gold\": {
|
25
|
+
\"_awesome_gold_strict\": true,
|
26
|
+
\"text_field\": \"awesome_gold\",
|
27
|
+
\"_awesome_gold_regex\": [\"\\\\.asdf\\\\.\", \"i\"]
|
28
|
+
}}]"
|
29
|
+
@c = Converters::JSAwesome.new(json)
|
30
|
+
#puts Parser.escape(@c.convert)
|
31
|
+
@c.convert.should sorta_match(<<-HTML)
|
32
|
+
<cf:text label="JSAwesome" default="default value">
|
33
|
+
<gold src="awesome_gold" regex="\\.asdf\\." flags="i" strict="true" />
|
34
|
+
</cf:text>
|
35
|
+
<cf:textarea label="Input some text with atleast one digit" required="true" />
|
36
|
+
<cf:select label="Single select">
|
37
|
+
<cf:option label="Boo" />
|
38
|
+
<cf:option label="Yah" />
|
39
|
+
</cf:select>
|
40
|
+
<cf:checkboxes label="Check">
|
41
|
+
<cf:checkbox label="One" name="totally_rad" />
|
42
|
+
<cf:checkbox label="Two" checked="true" />
|
43
|
+
<cf:checkbox label="Three" />
|
44
|
+
</cf:checkboxes>
|
45
|
+
<cf:radios label="Radio">
|
46
|
+
<cf:radio label="A" />
|
47
|
+
<cf:radio label="B" />
|
48
|
+
<cf:radio label="C" checked="true" />
|
49
|
+
</cf:radios>
|
50
|
+
<cf:hidden label="Hidden" value="hot" />
|
51
|
+
<cf:checkbox label="Single check" />
|
52
|
+
<cf:checkbox label="Edge" name="edge_case" default="false" />
|
53
|
+
HTML
|
54
|
+
end
|
55
|
+
end
|
data/spec/fixtures/complex.cfml
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
<h1>This is my name</h1>
|
2
2
|
<p>This is a description about me</p>
|
3
|
-
<cf:select label="Awesome" validations="required" instructions="Just be cool about it">
|
3
|
+
<cf:select label="Awesome" validations="required" default="Choose an option" instructions="Just be cool about it">
|
4
4
|
<cf:gold src="awesome_gold" regex="\\.asdf\\." flags="i" strict="true" />
|
5
|
-
<option
|
6
|
-
<option
|
7
|
-
<option
|
8
|
-
<option
|
9
|
-
<option>Neat</option>
|
5
|
+
<cf:option label="Awesome" />
|
6
|
+
<cf:option label="Cool" />
|
7
|
+
<cf:option label="Rad" />
|
8
|
+
<cf:option label="Neat" />
|
10
9
|
</cf:select>
|
11
10
|
<cf:text label="Opinion" validations="minLength:30" class="large" />
|
12
11
|
<cf:text label="Email" validations="required email" />
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<cf:select label="Awesome">
|
2
|
+
<cf:gold src="awesome_gold" regex="\\.asdf\\." flags="i" strict="true" />
|
3
|
+
<cf:option label="Awesome" />
|
4
|
+
<cf:option label="Rad" />
|
5
|
+
<cf:option label="Rad" />
|
6
|
+
<cf:option label="Neat" />
|
7
|
+
</cf:select>
|
8
|
+
<cf:text label="Opinion" validations="minLength:30" class="large" />
|
9
|
+
<cf:text label="Awesome" validations="required email" />
|
10
|
+
<cf:checkbox label="" value="yes" gold="true" />
|
@@ -1,23 +1,31 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "CFML Gold" do
|
4
|
-
it "should give me da gold" do
|
4
|
+
it "should give me da gold & fields" do
|
5
5
|
cfml = <<-HTML
|
6
|
-
<cf:checkboxes label="Checkboxes">
|
6
|
+
<cf:checkboxes label="Checkboxes" aggregation="all">
|
7
7
|
<cf:gold src="awesome_gold" regex="\\.asdf\\." flags="i" strict="true" />
|
8
8
|
<cf:checkbox label="Wanna do it?" />
|
9
9
|
<cf:checkbox label="Sure?" />
|
10
10
|
</cf:checkboxes>
|
11
|
-
<cf:
|
11
|
+
<cf:checkbox label="No way">
|
12
|
+
<cf:gold />
|
13
|
+
</cf:checkbox>
|
14
|
+
<cf:text name="cool" gold="true" aggregation="agg" />
|
12
15
|
<cf:textarea name="sweet" gold="sweetness" />
|
13
16
|
HTML
|
14
17
|
@p = Parser.new(cfml, :prefix => "u12345")
|
15
18
|
@p.golds.should == {
|
16
19
|
"_awesome_gold_strict" => "true",
|
17
|
-
"sweet" => "sweetness",
|
20
|
+
"sweet" => "sweetness",
|
21
|
+
"no_way" => "no_way_gold",
|
18
22
|
"checkboxes" => "awesome_gold",
|
19
23
|
"_awesome_gold_regex" => ["\\.asdf\\.", "i"],
|
20
24
|
"cool" => "cool_gold"
|
21
25
|
}
|
26
|
+
@p.fields.should == {
|
27
|
+
"checkboxes"=>"all",
|
28
|
+
"cool"=>"agg"
|
29
|
+
}
|
22
30
|
end
|
23
31
|
end
|
data/spec/tags/checkbox_spec.rb
CHANGED
@@ -61,6 +61,23 @@ describe "CFML Radio" do
|
|
61
61
|
HTML
|
62
62
|
end
|
63
63
|
|
64
|
+
it "should render gold" do
|
65
|
+
cfml = <<-HTML
|
66
|
+
<cf:checkbox label="Rad">
|
67
|
+
<cf:gold src="rad_gold"/>
|
68
|
+
</cf:checkbox>
|
69
|
+
HTML
|
70
|
+
@p = Parser.new(cfml, :prefix => "u12345")
|
71
|
+
@p.tags[0].should be_gold
|
72
|
+
@p.to_html.should sorta_match(<<-HTML)
|
73
|
+
<div class="cfml u12345">
|
74
|
+
<div class="checkbox">
|
75
|
+
<label><input type="checkbox" value="true" name="u12345[rad]" class="rad"/> Rad</label>
|
76
|
+
</div>
|
77
|
+
</div>
|
78
|
+
HTML
|
79
|
+
end
|
80
|
+
|
64
81
|
it "should render checkbox nested" do
|
65
82
|
cfml = <<-HTML
|
66
83
|
<div class="rando">
|
@@ -5,7 +5,8 @@ describe "CFML Checkboxes" do
|
|
5
5
|
cfml = <<-HTML
|
6
6
|
<cf:checkboxes label="Cool checkboxes">
|
7
7
|
<cf:checkbox label="Wanna do it?"/>
|
8
|
-
<cf:checkbox label="Sure?"
|
8
|
+
<cf:checkbox label="Sure?"/>
|
9
|
+
<cf:checkbox label="Not really..." value="nope" checked="true"/>
|
9
10
|
</cf:checkboxes>
|
10
11
|
HTML
|
11
12
|
@p = Parser.new(cfml, :prefix => "u12345")
|
@@ -19,6 +20,9 @@ describe "CFML Checkboxes" do
|
|
19
20
|
<label>
|
20
21
|
<input type="checkbox" value="Sure?" name="u12345[cool_checkboxes][]" class="cool_checkboxes"/> Sure?
|
21
22
|
</label>
|
23
|
+
<label>
|
24
|
+
<input type="checkbox" value="nope" checked="checked" name="u12345[cool_checkboxes][]" class="cool_checkboxes"/> Sure?
|
25
|
+
</label>
|
22
26
|
</fieldset>
|
23
27
|
</div>
|
24
28
|
HTML
|
data/spec/tags/select_spec.rb
CHANGED
@@ -4,9 +4,9 @@ describe "CFML Select" do
|
|
4
4
|
it "should render basic select" do
|
5
5
|
cfml = <<-HTML
|
6
6
|
<cf:select label="Basic">
|
7
|
-
<option>One</option>
|
8
|
-
<option>Two</option>
|
9
|
-
<option>Three</option>
|
7
|
+
<cf:option>One</option>
|
8
|
+
<cf:option>Two</option>
|
9
|
+
<cf:option>Three</option>
|
10
10
|
</cf:select>
|
11
11
|
HTML
|
12
12
|
@p = Parser.new(cfml, :prefix => "u12345")
|
@@ -23,4 +23,28 @@ describe "CFML Select" do
|
|
23
23
|
</div>
|
24
24
|
HTML
|
25
25
|
end
|
26
|
+
|
27
|
+
it "should render complex select" do
|
28
|
+
cfml = <<-HTML
|
29
|
+
<cf:select label="Basic" default="Choose an option">
|
30
|
+
<cf:option value="oney">One</option>
|
31
|
+
<cf:option selected="true">Two</option>
|
32
|
+
<cf:option label="Awesome"/>
|
33
|
+
</cf:select>
|
34
|
+
HTML
|
35
|
+
@p = Parser.new(cfml, :prefix => "u12345")
|
36
|
+
@p.to_html.should sorta_match(<<-HTML)
|
37
|
+
<div class="cfml u12345">
|
38
|
+
<div class="select">
|
39
|
+
<label>Basic</label>
|
40
|
+
<select name="u12345[basic]" class="basic">
|
41
|
+
<option value="">Choose an option</option>
|
42
|
+
<option value="oney">One</option>
|
43
|
+
<option selected="selected">Two</option>
|
44
|
+
<option>Awesome</option>
|
45
|
+
</select>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
HTML
|
49
|
+
end
|
26
50
|
end
|
data/spec/tags/text_spec.rb
CHANGED
@@ -19,7 +19,7 @@ describe "CFML Text" do
|
|
19
19
|
it "should render text with classes and instructions tag" do
|
20
20
|
cfml = <<-HTML
|
21
21
|
<cf:text label="Coolio" class="small">
|
22
|
-
<instructions>Just be <b>cool</b> bro!</instructions>
|
22
|
+
<cf:instructions>Just be <b>cool</b> bro!</cf:instructions>
|
23
23
|
</cf:text>
|
24
24
|
HTML
|
25
25
|
@p = Parser.new(cfml, :prefix => "u12345")
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "CFML Validation" do
|
4
|
+
it "adds errors if invalid" do
|
5
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/invalid.cfml"), {:prefix => "u12345"})
|
6
|
+
@p.should_not be_valid
|
7
|
+
@p.errors.should == [
|
8
|
+
["<cf:checkbox label=\"\" value=\"yes\" gold=\"true\"/>", "does not have a label or name specified."],
|
9
|
+
["<cf:text label=\"Awesome\" validations=\"required email\"/>", "has a duplicated name, please specify a unique name attribute."],
|
10
|
+
["<cf:option label=\"Rad\"/>", "a child of <cf:select label=\"Awesome\"> has a duplicated value, please specify a unique value attribute."]
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "oks valid cfml" do
|
15
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/complex.cfml"), {:prefix => "u12345"})
|
16
|
+
@p.valid?
|
17
|
+
@p.should be_valid
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dolores-cfml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Van Pelt
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-19 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: 1.3.3
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
36
|
+
name: json_pure
|
37
37
|
type: :runtime
|
38
38
|
version_requirement:
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- VERSION
|
61
61
|
- cfml.gemspec
|
62
62
|
- lib/cfml.rb
|
63
|
+
- lib/cfml/converters/jsawesome.rb
|
63
64
|
- lib/cfml/liquid_filters.rb
|
64
65
|
- lib/cfml/parser.rb
|
65
66
|
- lib/cfml/tag.rb
|
@@ -67,6 +68,7 @@ files:
|
|
67
68
|
- lib/cfml/tags/checkboxes.rb
|
68
69
|
- lib/cfml/tags/group.rb
|
69
70
|
- lib/cfml/tags/hidden.rb
|
71
|
+
- lib/cfml/tags/option.rb
|
70
72
|
- lib/cfml/tags/radio.rb
|
71
73
|
- lib/cfml/tags/radios.rb
|
72
74
|
- lib/cfml/tags/ratings.rb
|
@@ -75,20 +77,21 @@ files:
|
|
75
77
|
- lib/cfml/tags/textarea.rb
|
76
78
|
- lib/cfml/tags/unknown.rb
|
77
79
|
- spec/complex_spec.rb
|
80
|
+
- spec/converters/jsawesome_spec.rb
|
78
81
|
- spec/fixtures/complex.cfml
|
79
|
-
- spec/
|
82
|
+
- spec/fixtures/invalid.cfml
|
83
|
+
- spec/meta_spec.rb
|
80
84
|
- spec/sorta_match.rb
|
81
85
|
- spec/spec_helper.rb
|
82
86
|
- spec/tags/checkbox_spec.rb
|
83
87
|
- spec/tags/checkboxes_spec.rb
|
84
88
|
- spec/tags/group_spec.rb
|
85
89
|
- spec/tags/hidden_spec.rb
|
86
|
-
- spec/tags/radio_spec.rb
|
87
|
-
- spec/tags/radios_spec.rb
|
88
90
|
- spec/tags/select_spec.rb
|
89
91
|
- spec/tags/text_spec.rb
|
90
92
|
- spec/tags/textarea_spec.rb
|
91
93
|
- spec/tags/unknown_spec.rb
|
94
|
+
- spec/validation_spec.rb
|
92
95
|
has_rdoc: false
|
93
96
|
homepage: http://github.com/dolores/cfml
|
94
97
|
licenses:
|
@@ -118,16 +121,16 @@ specification_version: 3
|
|
118
121
|
summary: CFML is Crowd Flower Markup Language
|
119
122
|
test_files:
|
120
123
|
- spec/complex_spec.rb
|
121
|
-
- spec/
|
124
|
+
- spec/converters/jsawesome_spec.rb
|
125
|
+
- spec/meta_spec.rb
|
122
126
|
- spec/sorta_match.rb
|
123
127
|
- spec/spec_helper.rb
|
124
128
|
- spec/tags/checkbox_spec.rb
|
125
129
|
- spec/tags/checkboxes_spec.rb
|
126
130
|
- spec/tags/group_spec.rb
|
127
131
|
- spec/tags/hidden_spec.rb
|
128
|
-
- spec/tags/radio_spec.rb
|
129
|
-
- spec/tags/radios_spec.rb
|
130
132
|
- spec/tags/select_spec.rb
|
131
133
|
- spec/tags/text_spec.rb
|
132
134
|
- spec/tags/textarea_spec.rb
|
133
135
|
- spec/tags/unknown_spec.rb
|
136
|
+
- spec/validation_spec.rb
|
data/spec/tags/radio_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
|
3
|
-
describe "CFML Radio" do
|
4
|
-
#Doesn't make sense on its own but tested here anyway...
|
5
|
-
it "should render basic radio" do
|
6
|
-
cfml = <<-HTML
|
7
|
-
<cf:radio label="Rad"/>
|
8
|
-
HTML
|
9
|
-
@p = Parser.new(cfml, :prefix => "u12345")
|
10
|
-
@p.to_html.should sorta_match(<<-HTML)
|
11
|
-
<div class="cfml u12345">
|
12
|
-
<div class="radio">
|
13
|
-
<label><input type="radio" value="Rad" name="u12345[rad]" class="rad"/> Rad</label>
|
14
|
-
</div>
|
15
|
-
</div>
|
16
|
-
HTML
|
17
|
-
end
|
18
|
-
end
|
data/spec/tags/radios_spec.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
|
3
|
-
describe "CFML Radios" do
|
4
|
-
it "should render basic radios" do
|
5
|
-
cfml = <<-HTML
|
6
|
-
<cf:radios label="Cool radios">
|
7
|
-
<cf:radio label="Wanna do it?"/>
|
8
|
-
<cf:radio label="Sure!">
|
9
|
-
</cf:radios>
|
10
|
-
HTML
|
11
|
-
@p = Parser.new(cfml, :prefix => "u12345")
|
12
|
-
@p.to_html.should sorta_match(<<-HTML)
|
13
|
-
<div class="cfml u12345">
|
14
|
-
<fieldset class="radios">
|
15
|
-
<legend>Cool radios</legend>
|
16
|
-
<label>
|
17
|
-
<input type="radio" value="Wanna do it?" name="u12345[cool_radios]" class="cool_radios"/> Wanna do it?
|
18
|
-
</label>
|
19
|
-
<label>
|
20
|
-
<input type="radio" value="Sure!" name="u12345[cool_radios]" class="cool_radios"/> Sure!
|
21
|
-
</label>
|
22
|
-
</fieldset>
|
23
|
-
</div>
|
24
|
-
HTML
|
25
|
-
end
|
26
|
-
end
|