form 0.0.0 → 0.0.1.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/form/version.rb CHANGED
@@ -2,7 +2,7 @@ module Form
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- PATCH = 0
6
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
5
+ PATCH = 1
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.alpha1"
7
7
  end
8
8
  end
data/lib/form.rb CHANGED
@@ -1,3 +1,25 @@
1
+ require "i18n"
2
+ require "forwardable"
3
+
1
4
  module Form
5
+ autoload :Builder, "form/builder"
6
+ autoload :Component, "form/component"
7
+ autoload :Tag, "form/tag"
2
8
  autoload :Version, "form/version"
9
+
10
+ # Lazily add locale file to I18n.
11
+ #
12
+ def self.add_locale(locale)
13
+ I18n.load_path << File.expand_path("../form/locales/#{locale}.yml", __FILE__)
14
+ end
15
+
16
+ add_locale :en
17
+
18
+ # Initialize a new Form::Builder object.
19
+ #
20
+ # form = Form.new(params[:user], "user")
21
+ #
22
+ def self.new(data = nil, base_name = nil)
23
+ Builder.new(data, base_name)
24
+ end
3
25
  end
@@ -0,0 +1,95 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Builder do
4
+ describe "#initialize" do
5
+ let(:data) { mock }
6
+ let(:base_name) { mock }
7
+ subject { described_class.new(data, base_name) }
8
+
9
+ its(:data) { should eql(data) }
10
+ its(:base_name) { should eql(base_name) }
11
+ end
12
+
13
+ context "building fields" do
14
+ describe "#text" do
15
+ let(:component) { Form::Component::Input }
16
+ let(:type) { "text" }
17
+ let(:helper) { "text" }
18
+ it_behaves_like "input instantiation"
19
+ end
20
+
21
+ describe "#password" do
22
+ let(:component) { Form::Component::Input }
23
+ let(:type) { "password" }
24
+ let(:helper) { "password" }
25
+ it_behaves_like "input instantiation"
26
+ end
27
+
28
+ describe "#file" do
29
+ let(:component) { Form::Component::Input }
30
+ let(:type) { "file" }
31
+ let(:helper) { "file" }
32
+ it_behaves_like "input instantiation"
33
+ end
34
+
35
+ describe "#hidden" do
36
+ let(:component) { Form::Component::Input }
37
+ let(:type) { "hidden" }
38
+ let(:helper) { "hidden" }
39
+ it_behaves_like "input instantiation"
40
+ end
41
+
42
+ describe "#number" do
43
+ let(:component) { Form::Component::Input }
44
+ let(:type) { "number" }
45
+ let(:helper) { "number" }
46
+ it_behaves_like "input instantiation"
47
+ end
48
+
49
+ describe "#email" do
50
+ let(:component) { Form::Component::Input }
51
+ let(:type) { "email" }
52
+ let(:helper) { "email" }
53
+ it_behaves_like "input instantiation"
54
+ end
55
+
56
+ describe "#url" do
57
+ let(:component) { Form::Component::Input }
58
+ let(:type) { "url" }
59
+ let(:helper) { "url" }
60
+ it_behaves_like "input instantiation"
61
+ end
62
+
63
+ describe "#search" do
64
+ let(:component) { Form::Component::Input }
65
+ let(:type) { "search" }
66
+ let(:helper) { "search" }
67
+ it_behaves_like "input instantiation"
68
+ end
69
+
70
+ describe "#phone" do
71
+ let(:component) { Form::Component::Input }
72
+ let(:type) { "tel" }
73
+ let(:helper) { "phone" }
74
+ it_behaves_like "input instantiation"
75
+ end
76
+
77
+ describe "#textarea" do
78
+ let(:data) { mock("dataset").as_null_object }
79
+ let(:options) { mock("textarea options").as_null_object }
80
+ let(:textarea) { mock("textarea").as_null_object }
81
+ subject { described_class.new(data, :user) }
82
+
83
+ it "instantiates Form::Component::TextArea" do
84
+ Form::Component::TextArea.should_receive(:new).with(subject, :bio, options).and_return(textarea)
85
+ subject.textarea :bio, options
86
+ end
87
+
88
+ it "calls #to_html" do
89
+ Form::Component::TextArea.stub :new => textarea
90
+ textarea.should_receive(:to_html)
91
+ subject.textarea :bio
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Component::Base do
4
+ subject { described_class.new(nil, nil) }
5
+
6
+ describe "#composed_name" do
7
+ let(:form) { mock }
8
+ let(:name) { "name" }
9
+ subject { described_class.new(form, name) }
10
+
11
+ context "without base name" do
12
+ before { form.stub base_name: nil }
13
+ specify { subject.composed_name.should eql("name") }
14
+ end
15
+
16
+ context "for single base name" do
17
+ before { form.stub base_name: "user" }
18
+ specify { subject.composed_name.should eql("user[name]") }
19
+ end
20
+
21
+ context "for multiple base name" do
22
+ before { form.stub base_name: ["user", "profile"] }
23
+ specify { subject.composed_name.should eql("user[profile][name]") }
24
+ end
25
+ end
26
+
27
+ describe "#data" do
28
+ let(:form) { mock.as_null_object }
29
+ subject { described_class.new(form, "name") }
30
+
31
+ it "delegates to form's data" do
32
+ form.should_receive(:data).once
33
+ subject.data
34
+ end
35
+ end
36
+
37
+ describe "#value" do
38
+ let(:form) { mock }
39
+ let(:name) { "name" }
40
+ subject { described_class.new(form, name) }
41
+
42
+ context "with objects that respond to []" do
43
+ it "returns value for string key" do
44
+ form.stub data: {"name" => "John Doe"}
45
+ subject.value.should eql("John Doe")
46
+ end
47
+
48
+ it "returns value for symbol key" do
49
+ form.stub data: {:name => "John Doe"}
50
+ subject.value.should eql("John Doe")
51
+ end
52
+ end
53
+
54
+ context "with objects that respond to the attribute" do
55
+ it "returns value" do
56
+ form.stub data: mock(name: "John Doe")
57
+ subject.value.should eql("John Doe")
58
+ end
59
+ end
60
+
61
+ context "with no data objects" do
62
+ it "returns nil" do
63
+ form.stub :data
64
+ subject.value.should be_nil
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#t" do
70
+ it "proxies arguments to I18n.t" do
71
+ I18n.should_receive(:t).with(:a, :b)
72
+ subject.t(:a, :b)
73
+ end
74
+ end
75
+
76
+ describe "#humanize" do
77
+ specify { subject.humanize("name").should eql("Name") }
78
+ specify { subject.humanize("full_name").should eql("Full name") }
79
+ end
80
+ end
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Component::Input do
4
+ end
@@ -0,0 +1,56 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Component::Label do
4
+ describe "#text" do
5
+ let(:form) { mock(base_name: nil) }
6
+ subject { described_class.new(form, :email) }
7
+
8
+ context "with simple name" do
9
+ it "returns specified text" do
10
+ subject.options[:text] = "E-mail address"
11
+ subject.text.should eql("E-mail address")
12
+ end
13
+
14
+ it "returns text for full scope" do
15
+ i18n :en, {form: {
16
+ labels: {email: "E-mail"}
17
+ }}
18
+
19
+ subject.text.should eql("E-mail")
20
+ end
21
+
22
+ it "returns humanized text" do
23
+ subject.text.should eql("Email")
24
+ end
25
+ end
26
+
27
+ context "with composed name" do
28
+ before { form.stub base_name: %w[user profile] }
29
+
30
+ it "returns specified text" do
31
+ subject.options[:text] = "E-mail address"
32
+ subject.text.should eql("E-mail address")
33
+ end
34
+
35
+ it "returns text for full scope" do
36
+ i18n :en, {form: {
37
+ labels: {user: {profile: {email: "E-mail"}}}
38
+ }}
39
+
40
+ subject.text.should eql("E-mail")
41
+ end
42
+
43
+ it "returns text for root scope" do
44
+ i18n :en, {form: {
45
+ labels: {email: "E-mail"}
46
+ }}
47
+
48
+ subject.text.should eql("E-mail")
49
+ end
50
+
51
+ it "returns humanized text" do
52
+ subject.text.should eql("Email")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Component::TextArea do
4
+ context "with defaults" do
5
+ let(:form) { mock(:base_name => nil, :data => nil) }
6
+ subject { described_class.new(form, :bio) }
7
+
8
+ it "includes cols" do
9
+ subject.attributes[:cols].should eql(50)
10
+ end
11
+
12
+ it "includes rows" do
13
+ subject.attributes[:rows].should eql(5)
14
+ end
15
+
16
+ it "includes name" do
17
+ subject.attributes[:name].should eql("bio")
18
+ end
19
+
20
+ it "returns html" do
21
+ html = subject.to_html
22
+
23
+ html.should have_tag(:textarea, :count => 1)
24
+ html.should have_tag("[cols='50']")
25
+ html.should have_tag("[rows='5']")
26
+ html.should have_tag("[name='bio']")
27
+ end
28
+ end
29
+
30
+ context "with custom options" do
31
+ let(:form) { mock(:base_name => :user, :data => nil) }
32
+ subject {
33
+ described_class.new(form, :bio,
34
+ :autofocus => true,
35
+ :rows => 10,
36
+ :cols => 25
37
+ )
38
+ }
39
+
40
+ it "includes cols" do
41
+ subject.attributes[:cols].should eql(25)
42
+ end
43
+
44
+ it "includes rows" do
45
+ subject.attributes[:rows].should eql(10)
46
+ end
47
+
48
+ it "includes name" do
49
+ subject.attributes[:name].should eql("user[bio]")
50
+ end
51
+
52
+ it "returns html" do
53
+ html = subject.to_html
54
+
55
+ html.should have_tag(:textarea, :count => 1)
56
+ html.should have_tag("[cols='25']")
57
+ html.should have_tag("[rows='10']")
58
+ html.should have_tag("[name='user[bio]']")
59
+ html.should have_tag("[autofocus]")
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash, "extensions" do
4
+ describe "#except" do
5
+ it "skips specified keys" do
6
+ {a: 1, b: 2, c: 3}.except(:a, :c).should eql(b: 2)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+ describe Form::Tag do
4
+ subject { described_class.new(:p) }
5
+
6
+ describe "#initialize" do
7
+ it "yields instance" do
8
+ tag = nil
9
+ described_class.new(:p) {|t| tag = t}
10
+ tag.should be_a(described_class)
11
+ end
12
+
13
+ it "evaluates block" do
14
+ tag = nil
15
+ described_class.new(:p) { tag = self }
16
+ tag.should be_a(described_class)
17
+ end
18
+
19
+ context "argument position" do
20
+ it "moves position" do
21
+ tag = described_class.new(:p, class: "hello")
22
+ tag.attributes.should eql(class: "hello")
23
+ tag.content.should eql("")
24
+ end
25
+
26
+ it "keeps position" do
27
+ tag = described_class.new(:p, "Hello", class: "hello")
28
+ tag.attributes.should eql(class: "hello")
29
+ tag.content.should eql("Hello")
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#<<" do
35
+ it "appends content" do
36
+ tag = described_class.new(:p)
37
+ tag << "Hello"
38
+ tag.to_s.should eql("<p>Hello</p>")
39
+ end
40
+ end
41
+
42
+ describe "#void?" do
43
+ it "detects void tag" do
44
+ subject = described_class.new(:br)
45
+ subject.should be_void
46
+ end
47
+
48
+ it "rejects as open tag" do
49
+ subject = described_class.new(:p)
50
+ subject.should_not be_void
51
+ end
52
+ end
53
+
54
+ describe "#to_s" do
55
+ it "renders tag" do
56
+ subject = described_class.new(:p, "Hello")
57
+ subject.to_s.should eql("<p>Hello</p>")
58
+ end
59
+
60
+ it "renders tag with attributes" do
61
+ subject = described_class.new(:p, "Hello", class: "hello")
62
+ subject.to_s.should eql(%[<p class="hello">Hello</p>])
63
+ end
64
+
65
+ it "renders open tag" do
66
+ subject = described_class.new(:hr)
67
+ subject.to_s.should eql("<hr>")
68
+ end
69
+
70
+ it "renders open tag with attributes" do
71
+ subject = described_class.new(:hr, class: "separator")
72
+ subject.to_s.should eql(%[<hr class="separator">])
73
+ end
74
+
75
+ it "renders boolean attributes" do
76
+ subject = described_class.new(:input, autofocus: true)
77
+ subject.to_s.should eql("<input autofocus>")
78
+ end
79
+
80
+ it "skips attributes with false value" do
81
+ subject = described_class.new(:input, autofocus: false)
82
+ subject.to_s.should eql("<input>")
83
+ end
84
+
85
+ it "skips attributes with empty value" do
86
+ subject = described_class.new(:input, value: "")
87
+ subject.to_s.should eql("<input>")
88
+ end
89
+
90
+ it "escapes attribute value" do
91
+ subject = described_class.new(:img, alt: "<3")
92
+ subject.to_s.should eql(%[<img alt="&lt;3">])
93
+ end
94
+ end
95
+
96
+ describe "#tag" do
97
+ it "renders simple tag" do
98
+ subject = described_class.new(:p)
99
+ subject.tag(:strong, "Hello")
100
+ subject.to_s.should eql("<p><strong>Hello</strong></p>")
101
+ end
102
+
103
+ it "renders complex tag" do
104
+ subject = described_class.new(:form, action: "some/path") do |form|
105
+ form.tag :p do |p|
106
+ p.tag :label, "E-mail", for: "user_email"
107
+ p.tag :input, type: "email", autofocus: true
108
+ end
109
+ end
110
+
111
+ subject.to_s.should have_tag("form[action='some/path']") do |form|
112
+ form.should have_tag("p") do |p|
113
+ p.should have_tag("label[for=user_email]")
114
+ p.should have_tag("input[type=email][autofocus]")
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end