dolores-cml 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Van Pelt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = cml
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 Chris Van Pelt. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "cml"
8
+ gem.summary = "CML is CrowdFlower Markup Language"
9
+ gem.description = "CML let's you easily create form elements and custom interfaces for the CrowdFlower Croud Labor platform"
10
+ gem.email = "vanpelt@doloreslabs.com"
11
+ gem.homepage = "http://github.com/dolores/cml"
12
+ gem.authors = ["Chris Van Pelt"]
13
+ gem.add_dependency 'liquid', '>= 2.0.0'
14
+ gem.add_dependency 'nokogiri', '>= 1.3.3'
15
+ gem.add_dependency 'json_pure', '>= 1.1.3'
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :refresh_builder => [:build] do
36
+ cp "pkg/cml-#{File.read("VERSION").strip}.gem", "../builder/gems/cache/"
37
+ rm_rf "../builder/gems/gems/cml-#{File.read("VERSION").strip}/"
38
+ `cd ../builder && bin/thor merb:gem:redeploy`
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION.yml')
46
+ config = YAML.load(File.read('VERSION.yml'))
47
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "cml #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
data/cml.gemspec ADDED
@@ -0,0 +1,103 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{cml}
5
+ s.version = "0.3.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Chris Van Pelt"]
9
+ s.date = %q{2009-08-25}
10
+ s.description = %q{CML let's you easily create form elements and custom interfaces for the CrowdFlower Croud Labor platform}
11
+ s.email = %q{vanpelt@doloreslabs.com}
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = [
17
+ ".document",
18
+ ".gitignore",
19
+ "LICENSE",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "cml.gemspec",
24
+ "lib/cml.rb",
25
+ "lib/cml/converters/jsawesome.rb",
26
+ "lib/cml/liquid_filters.rb",
27
+ "lib/cml/parser.rb",
28
+ "lib/cml/tag.rb",
29
+ "lib/cml/tags/checkbox.rb",
30
+ "lib/cml/tags/checkboxes.rb",
31
+ "lib/cml/tags/group.rb",
32
+ "lib/cml/tags/hidden.rb",
33
+ "lib/cml/tags/meta.rb",
34
+ "lib/cml/tags/option.rb",
35
+ "lib/cml/tags/radio.rb",
36
+ "lib/cml/tags/radios.rb",
37
+ "lib/cml/tags/ratings.rb",
38
+ "lib/cml/tags/select.rb",
39
+ "lib/cml/tags/text.rb",
40
+ "lib/cml/tags/textarea.rb",
41
+ "lib/cml/tags/unknown.rb",
42
+ "spec/complex_spec.rb",
43
+ "spec/converters/jsawesome_spec.rb",
44
+ "spec/fixtures/complex.cml",
45
+ "spec/fixtures/invalid.cml",
46
+ "spec/meta_spec.rb",
47
+ "spec/sorta_match.rb",
48
+ "spec/spec_helper.rb",
49
+ "spec/tags/checkbox_spec.rb",
50
+ "spec/tags/checkboxes_spec.rb",
51
+ "spec/tags/group_spec.rb",
52
+ "spec/tags/hidden_spec.rb",
53
+ "spec/tags/meta_spec.rb",
54
+ "spec/tags/radios_spec.rb",
55
+ "spec/tags/select_spec.rb",
56
+ "spec/tags/text_spec.rb",
57
+ "spec/tags/textarea_spec.rb",
58
+ "spec/tags/unknown_spec.rb",
59
+ "spec/validation_spec.rb"
60
+ ]
61
+ s.homepage = %q{http://github.com/dolores/cml}
62
+ s.rdoc_options = ["--charset=UTF-8"]
63
+ s.require_paths = ["lib"]
64
+ s.rubygems_version = %q{1.3.4}
65
+ s.summary = %q{CML is CrowdFlower Markup Language}
66
+ s.test_files = [
67
+ "spec/complex_spec.rb",
68
+ "spec/converters/jsawesome_spec.rb",
69
+ "spec/meta_spec.rb",
70
+ "spec/sorta_match.rb",
71
+ "spec/spec_helper.rb",
72
+ "spec/tags/checkbox_spec.rb",
73
+ "spec/tags/checkboxes_spec.rb",
74
+ "spec/tags/group_spec.rb",
75
+ "spec/tags/hidden_spec.rb",
76
+ "spec/tags/meta_spec.rb",
77
+ "spec/tags/radios_spec.rb",
78
+ "spec/tags/select_spec.rb",
79
+ "spec/tags/text_spec.rb",
80
+ "spec/tags/textarea_spec.rb",
81
+ "spec/tags/unknown_spec.rb",
82
+ "spec/validation_spec.rb"
83
+ ]
84
+
85
+ if s.respond_to? :specification_version then
86
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
87
+ s.specification_version = 3
88
+
89
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
90
+ s.add_runtime_dependency(%q<liquid>, [">= 2.0.0"])
91
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.3"])
92
+ s.add_runtime_dependency(%q<json_pure>, [">= 1.1.3"])
93
+ else
94
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
95
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
96
+ s.add_dependency(%q<json_pure>, [">= 1.1.3"])
97
+ end
98
+ else
99
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
100
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
101
+ s.add_dependency(%q<json_pure>, [">= 1.1.3"])
102
+ end
103
+ end
@@ -0,0 +1,102 @@
1
+ module CML
2
+ module Converters
3
+ class JSAwesome
4
+ def initialize(json)
5
+ parsed = JSON.parse(json)
6
+ @json = parsed[0] || []
7
+ @labels = parsed[1] || {}
8
+ @tags = []
9
+ end
10
+
11
+ def convert
12
+ @json.map do |k,v|
13
+ if k.is_a?(Array)
14
+ (k << v).map {|k,v| process(k,v)}
15
+ else
16
+ process(k,v)
17
+ end
18
+ end.join("\n") + meta
19
+ end
20
+
21
+ def meta
22
+ (@labels["gold"] || {}).select do |k,v|
23
+ next if k =~ /^_/
24
+ !@tags.map {|t| t.name }.include?(k)
25
+ end.map do |k,v|
26
+ tag("meta", k, {:meta => true})
27
+ end.join("\n")
28
+ end
29
+
30
+ def label(k)
31
+ k = k.sub(/^[_#*^~]?\+?/,'')
32
+ l = @labels[k]
33
+ label = l.is_a?(Hash) ? l["label"] : l if l
34
+ label ||= k.capitalize.gsub(/_/,' ')
35
+ end
36
+
37
+ def tag(tag, val, opts = {})
38
+ val = Array(val)
39
+ parts = val[0].split("|")
40
+ key = parts[0].sub(/^[_#*^~]?\+?/,'')
41
+ label = label(parts[0])
42
+ parts << key if label != key.capitalize.gsub(/_/,' ') || opts[:meta]
43
+ attrs = opts[:meta] ? [] : ["label=\"#{label}\""]
44
+ attrs << "name=\"#{parts[1]}\"" if parts[1]
45
+ attrs << "checked=\"true\"" if val[1]
46
+ attrs << "validates=\"required\"" if @labels[key] && @labels[key]["required"]
47
+ opts.reject {|k,v| v.to_s.strip.length == 0 || k.is_a?(Symbol) }.each do |k,v|
48
+ attrs << "#{k}=\"#{v}\""
49
+ end
50
+ if @labels["gold"] && @labels["gold"][key]
51
+ opts["gold"] = {}
52
+ src = @labels["gold"][key]
53
+ opts["gold"]["src"] = src
54
+ opts["gold"]["regex"], opts["gold"]["flags"] = Array(@labels["gold"]["_"+src+"_regex"])
55
+ opts["gold"]["strict"] = @labels["gold"]["_"+src+"_strict"]
56
+ else
57
+ opts["gold"] = false
58
+ end
59
+
60
+ tag = Parser.tag_class(tag).new("<cml:#{tag} #{attrs.join(" ")} />")
61
+ tag.gold = opts["gold"]
62
+ opts[:children].each { |c| tag.cml.add_child(tag(*c).cml) } if opts[:children]
63
+ @tags << tag if opts[:parent]
64
+ tag
65
+ end
66
+
67
+ def process(k,v)
68
+ select_default = @labels['{}'] || "Choose Category"
69
+ cml = case v
70
+ #a select tag or group of radios/checkboxes
71
+ when Array:
72
+ if(k =~ /^[^_]/)
73
+ if $~[0] == "*"
74
+ parent = "radios"
75
+ child = "radio"
76
+ elsif $~[0] == "^"
77
+ parent = "checkboxes"
78
+ child = "checkbox"
79
+ else
80
+ parent = "select"
81
+ child = "option"
82
+ end
83
+ tag(parent, k, {:children => v.map { |c| [child, c]}, :parent => true })
84
+ #Multiple hidden fields...
85
+ elsif(k =~ /^_/)
86
+ v.map { |c| tag("hidden", c, :parent => true)}.join("\n")
87
+ end
88
+ else
89
+ if(k =~ /^#/)
90
+ tag("textarea", k, {"default" => v, :parent => true})
91
+ elsif(k =~ /^_/)
92
+ tag("hidden", k, {"value" => v, :parent => true})
93
+ elsif(k =~ /^\^/)
94
+ tag("checkbox", k, {"default" => v, :parent => true})
95
+ else
96
+ tag("text", k, {"default" => v, :parent => true})
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,7 @@
1
+ module CML
2
+ module LiquidFilters
3
+ def to_json(input)
4
+ input.to_json
5
+ end
6
+ end
7
+ end
data/lib/cml/parser.rb ADDED
@@ -0,0 +1,107 @@
1
+ module CML
2
+ class Parser
3
+ attr_reader :doc, :cftags, :tags, :errors
4
+
5
+ def initialize(content, opts = {})
6
+ @opts = opts
7
+ @doc = Parser.parse(content)
8
+ @cftags = @doc.xpath("//cml:*[not(ancestor::cml:*)]")
9
+ @tags = @cftags.map do |t|
10
+ Parser.tag_class(t.name).new(t, @opts)
11
+ end
12
+ end
13
+
14
+ def self.parse(content)
15
+ Nokogiri::XML("<root xmlns:cml=\"http://crowdflower.com\">#{content}</root>")
16
+ end
17
+
18
+ def convert(opts = nil)
19
+ @opts = opts if opts
20
+ cloned = @doc.dup
21
+ cloned.xpath("//cml:*[not(ancestor::cml:*)]").each_with_index do |t,i|
22
+ t.replace(@tags[i].convert(opts))
23
+ end
24
+ cloned
25
+ end
26
+
27
+ def fields
28
+ @fields = {}
29
+ @tags.each do |g|
30
+ agg = g.attrs["aggregation"]
31
+ @fields[g.name] = agg.to_s if agg
32
+ end
33
+ @fields
34
+ end
35
+
36
+ def golds
37
+ return @golds if @golds
38
+ @golds = {}
39
+ @tags.each do |g|
40
+ gold = g.gold?
41
+ next unless gold
42
+ val = (gold.attributes["gold"] || gold.attributes["src"]).to_s
43
+ val = "#{g.name}_gold" if val =~ /^(true|\s*)$/
44
+ @golds[g.name] = val
45
+ ["strict","regex"].each do |attrs|
46
+ if a = gold.attributes[attrs]
47
+ @golds["_#{val}_#{attrs}"] = attrs == "regex" ? [a.to_s, gold.attributes["flags"].to_s] : a.to_s
48
+ end
49
+ end
50
+ end
51
+ @golds
52
+ end
53
+
54
+ def valid?
55
+ @errors = []
56
+ if e = @doc.errors.select {|e| s.fatal? }.last
57
+ @errors << "Malformed CML (#{e.level}). #{e.message.chomp} on line #{e.line} column #{e.column}."
58
+ end
59
+ @tags.select {|t| t.validate? && t.name =~ /^\s*$/ }.each do |t|
60
+ @errors << "#{t.to_s.split("\n")[0]} does not have a label or name specified."
61
+ end
62
+ dupes = @tags.select do |tag|
63
+ tag.validate? && @tags.select {|t| t.name == tag.name}.length > 1
64
+ end
65
+ (dupes[1..-1] || []).each do |t|
66
+ @errors << "#{t.to_s.split("\n")[0]} has a duplicated name, please specify a unique name attribute."
67
+ end
68
+ @tags.each do |t|
69
+ next unless t.children
70
+ dupes = t.children.select do |child|
71
+ t.children.select {|c| c.value == child.value}.length > 1
72
+ end
73
+ (dupes[1..-1] || []).each do |c|
74
+ @errors << "#{c} a child of #{t.to_s.split("\n")[0]} has a duplicated value, please specify a unique value attribute."
75
+ end
76
+ end
77
+ @errors.length == 0
78
+ end
79
+
80
+ def wrap(content)
81
+ @opts[:no_wrap] ? content : "<div class=\"cml#{" "+@opts[:class] if @opts[:class]}\" id=\"#{@opts[:prefix]}\">#{content}</div>"
82
+ end
83
+
84
+ def to_s
85
+ @doc.root.children.to_s
86
+ end
87
+
88
+ def to_html(opts = nil)
89
+ xml = convert(opts)
90
+ wrap(xml.at("root").inner_html)
91
+ end
92
+
93
+ def self.escape( string )
94
+ string.to_s.gsub( /&/, "&amp;" ).
95
+ gsub( /</, "&lt;" ).
96
+ gsub( />/, "&gt;" ).
97
+ gsub( /"/, "&quot;" )
98
+ end
99
+
100
+ #This takes the name of the tag and converts it to the appropriate task
101
+ def self.tag_class(name)
102
+ CML::Tags.module_eval(name.gsub(/(^|_)(.)/) { $2.upcase })
103
+ rescue
104
+ CML::Tags::Unknown
105
+ end
106
+ end
107
+ end
data/lib/cml/tag.rb ADDED
@@ -0,0 +1,134 @@
1
+ module CML
2
+ class Tag
3
+ attr_reader :attrs, :tag, :data, :cml
4
+
5
+ def initialize(cml, opts = {})
6
+ @cml = cml.is_a?(String) ? Parser.parse(cml).at("/root/*") : cml
7
+ @attrs = @cml.attributes#Hash[*cml.attributes.map {|k,v| [k.intern,v]}.flatten]
8
+ @tag = @cml.name
9
+ @opts = opts
10
+ end
11
+
12
+ def prefix(name)
13
+ @opts[:prefix] ? "#{@opts[:prefix]}[#{name}]" : "#{name}"
14
+ end
15
+
16
+ def gold?
17
+ @attrs["gold"] ? @cml : @cml.at("./cml:gold")
18
+ end
19
+
20
+ def gold=(opts = {})
21
+ cur = gold?
22
+ advanced = ["strict", "regex"].any? {|k| opts && opts[k] }
23
+ if !cur
24
+ cur = advanced ? @cml.add_child(Parser.parse("<cml:gold/>").at("/root/*")) : @cml
25
+ end
26
+
27
+ if cur.name == "gold"
28
+ if !opts
29
+ cur.remove
30
+ elsif advanced
31
+ opts.each do |k,v|
32
+ cur[k] = v.to_s if v
33
+ end
34
+ else
35
+ cur.remove
36
+ cur = @cml
37
+ end
38
+ end
39
+
40
+ if cur.name != "gold"
41
+ if !opts
42
+ @cml.remove_attribute("gold")
43
+ elsif opts["src"] && opts["src"] != "#{name}_gold"
44
+ @cml["gold"] = opts["src"]
45
+ else
46
+ @cml["gold"] = "true"
47
+ end
48
+ end
49
+ end
50
+
51
+ def name
52
+ (@attrs["name"] || @attrs["label"]).to_s.downcase.gsub(/\s/,"_").gsub(/\W/,"")
53
+ end
54
+
55
+ def wrapper_classes
56
+ extras = @attrs["only-if"] ? "only-if:#{@attrs["only-if"]}" : ""
57
+ "#{@tag} #{extras}".strip
58
+ end
59
+
60
+ def children
61
+ false
62
+ end
63
+
64
+ def classes
65
+ @classes ||= [name] << validations << @attrs["class"].to_s.split(/ /)
66
+ @classes.uniq.reject {|c| c.length == 0 }.join(" ").strip
67
+ end
68
+
69
+ def convert(opts = nil)
70
+ @opts = opts if opts
71
+ html = to_html
72
+ html.strip.length == 0 ? Nokogiri::XML::Text.new(html, @cml.document) : Nokogiri::HTML.fragment(html)
73
+ end
74
+
75
+ def to_html
76
+ wrapper(Liquid::Template.parse(self.class::Template).render(data, [LiquidFilters]))
77
+ end
78
+
79
+ def to_s
80
+ @cml.to_s
81
+ end
82
+
83
+ def label(label, tag = "label")
84
+ label ||= @attrs["name"].to_s.capitalize
85
+ required = " <span class=\"required\">(required)</span>" if validations.include?("required")
86
+ "<#{tag}>#{label}#{required}</#{tag.split(" ")[0]}>" if label.to_s != ""
87
+ end
88
+
89
+ def legend(label)
90
+ label(label, "legend") if label
91
+ end
92
+
93
+ def to_liquid
94
+ to_html
95
+ end
96
+
97
+ def validations
98
+ @validations ||= @attrs["validates"].to_s.split(/ /).map {|v| "validates-#{v}"}
99
+ end
100
+
101
+ def instructions
102
+ @instructions ||= @attrs["instructions"] || (@cml.at("./cml:instructions") ? @cml.at("./cml:instructions").inner_html : nil)
103
+ @instructions ? "<p class=\"instructions\">#{@instructions}</p>" : nil
104
+ end
105
+
106
+ def validate?
107
+ true
108
+ end
109
+
110
+ def wrapper(parsed, tag = "div")
111
+ #Deal with a label only wrapper... kinda jank
112
+ if tag == "label" && instructions
113
+ tag = "div"
114
+ parsed = "<label>#{parsed}</label>"
115
+ end
116
+ #Inserting instructions here makes it a non-variable input maybe...
117
+ "<#{tag} class=\"#{wrapper_classes}\">#{parsed}#{instructions}</#{tag}>"
118
+ end
119
+
120
+ def value
121
+ @attrs["value"].to_s
122
+ end
123
+
124
+ def data
125
+ (@opts[:data] || {}).merge({
126
+ "name" => prefix(name),
127
+ "label" => label(@attrs["label"]),
128
+ "legend" => label(@attrs["label"], "h2 class=\"legend\""),
129
+ "classes" => classes,
130
+ "value" => value
131
+ })
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,37 @@
1
+ module CML
2
+ module Tags
3
+ class Checkbox < Tag
4
+ Template = <<-HTML.freeze
5
+ {{default}}
6
+ <label><input name="{{name}}" type="checkbox" value="{{value}}" class="{{classes}}" {{checked}}/> {{label}}</label>
7
+ HTML
8
+
9
+ def prefix(name)
10
+ super(name) + (grouped? ? "[]" : "")
11
+ end
12
+
13
+ def grouped?
14
+ @cml.parent && @cml.parent.name == "checkboxes"
15
+ end
16
+
17
+ def wrapper(parsed)
18
+ grouped? ? parsed : super
19
+ end
20
+
21
+ def value
22
+ (@attrs["value"] || (grouped? ? @attrs["label"] : "true")).to_s
23
+ end
24
+
25
+ def data
26
+ default = ""
27
+ if @attrs["default"]
28
+ default = Hidden.new("<cml:hidden name=\"#{name}\" value=\"#{@attrs["default"]}\"/>", @opts).to_html
29
+ end
30
+ super.merge({
31
+ "default" => default,
32
+ "checked" => @attrs["checked"] ? "checked=\"checked\"" : "",
33
+ "label" => @attrs["label"].to_s})
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ module CML
2
+ module Tags
3
+ class Checkboxes < Tag
4
+ Template = <<-HTML.freeze
5
+ {{legend}}
6
+ {% for checkbox in checkboxes %}
7
+ {{checkbox}}
8
+ {% endfor %}
9
+ HTML
10
+
11
+ def data
12
+ super.merge({"checkboxes" => children})
13
+ end
14
+
15
+ def children
16
+ @cml.xpath("cml:checkbox").map do |c|
17
+ c["name"] ||= name
18
+ c["validates"] ||= @attrs["validates"].to_s
19
+ Checkbox.new(c, @opts)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module CML
2
+ module Tags
3
+ class Group < Tag
4
+ Template = <<-HTML.freeze
5
+ {{label}}
6
+ {{content}}
7
+ HTML
8
+
9
+ def validate?
10
+ false
11
+ end
12
+
13
+ def data
14
+ super.merge({"content" => Parser.new(@cml.inner_html, @opts.merge(:no_wrap => true)).to_html})
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module CML
2
+ module Tags
3
+ class Hidden < Tag
4
+ Template = <<-HTML.freeze
5
+ <input name="{{name}}" type="hidden" value="{{value}}" class="{{classes}}"/>
6
+ HTML
7
+
8
+ def wrapper(parsed)
9
+ parsed
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module CML
2
+ module Tags
3
+ class Meta < Tag
4
+ Template = <<-HTML.freeze
5
+ HTML
6
+
7
+ def wrapper(parsed)
8
+ parsed
9
+ end
10
+ end
11
+ end
12
+ end