formulary 0.0.2 → 0.0.3
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.
- checksums.yaml +7 -0
- data/README.md +65 -34
- data/formulary.gemspec +0 -1
- data/lib/formulary.rb +1 -5
- data/lib/formulary/html_form.rb +31 -13
- data/lib/formulary/html_form/fields.rb +16 -0
- data/lib/formulary/html_form/fields/checkbox_group.rb +1 -1
- data/lib/formulary/html_form/fields/color_input.rb +24 -0
- data/lib/formulary/html_form/fields/date_input.rb +59 -0
- data/lib/formulary/html_form/fields/email_input.rb +11 -2
- data/lib/formulary/html_form/fields/field.rb +15 -3
- data/lib/formulary/html_form/fields/field_group.rb +3 -3
- data/lib/formulary/html_form/fields/input.rb +1 -1
- data/lib/formulary/html_form/fields/month_input.rb +15 -0
- data/lib/formulary/html_form/fields/number_input.rb +63 -0
- data/lib/formulary/html_form/fields/password_input.rb +7 -0
- data/lib/formulary/html_form/fields/range_input.rb +7 -0
- data/lib/formulary/html_form/fields/search_input.rb +7 -0
- data/lib/formulary/html_form/fields/select.rb +1 -1
- data/lib/formulary/html_form/fields/week_input.rb +15 -0
- data/lib/formulary/html_form/labels.rb +39 -0
- data/lib/formulary/version.rb +1 -1
- data/spec/html_form/fields/checkbox_group_spec.rb +23 -10
- data/spec/html_form/fields/color_input_spec.rb +58 -0
- data/spec/html_form/fields/date_input_spec.rb +60 -0
- data/spec/html_form/fields/email_input_spec.rb +16 -6
- data/spec/html_form/fields/field_spec.rb +40 -1
- data/spec/html_form/fields/hidden_input_spec.rb +3 -1
- data/spec/html_form/fields/month_input_spec.rb +60 -0
- data/spec/html_form/fields/number_input_spec.rb +67 -0
- data/spec/html_form/fields/password_input_spec.rb +29 -0
- data/spec/html_form/fields/radio_button_group_spec.rb +27 -8
- data/spec/html_form/fields/range_input_spec.rb +20 -0
- data/spec/html_form/fields/search_input_spec.rb +18 -0
- data/spec/html_form/fields/select_spec.rb +10 -7
- data/spec/html_form/fields/tel_input_spec.rb +3 -3
- data/spec/html_form/fields/text_input_spec.rb +3 -3
- data/spec/html_form/fields/textarea_spec.rb +2 -2
- data/spec/html_form/fields/week_input_spec.rb +60 -0
- data/spec/html_form_spec.rb +234 -100
- data/spec/support/element_helper.rb +1 -1
- data/spec/support/shared_examples_for_pattern.rb +4 -2
- data/spec/support/shared_examples_for_required.rb +4 -2
- metadata +114 -106
@@ -6,8 +6,8 @@ module Formulary::HtmlForm::Fields
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
def initialize(group_name, elements)
|
10
|
-
@group_name, @elements = group_name, elements
|
9
|
+
def initialize(html_form, group_name, elements)
|
10
|
+
@html_form, @group_name, @elements = html_form, group_name, elements
|
11
11
|
end
|
12
12
|
|
13
13
|
def name
|
@@ -20,7 +20,7 @@ module Formulary::HtmlForm::Fields
|
|
20
20
|
|
21
21
|
def error
|
22
22
|
return super if super.present?
|
23
|
-
return "
|
23
|
+
return "'#{label}' must be chosen from the available options" if !value_in_list?
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Formulary::HtmlForm::Fields
|
2
|
+
class NumberInput < Input
|
3
|
+
def self.compatible_type
|
4
|
+
"number"
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(html_form, element)
|
8
|
+
@html_form, @element = html_form, element
|
9
|
+
@min = @element.attributes['min'].try('value')
|
10
|
+
@max = @element.attributes['max'].try('value')
|
11
|
+
@step = @element.attributes['step'].try('value')
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
super && number_correct? && min_correct? && max_correct? && step_correct?
|
16
|
+
end
|
17
|
+
|
18
|
+
def error
|
19
|
+
return super if super.present?
|
20
|
+
return "'#{label}' must be a valid number" unless number_correct?
|
21
|
+
return "'#{label}' must be greater than or equal to #{@min}" unless min_correct?
|
22
|
+
return "'#{label}' must be less than or equal to #{@max}" unless max_correct?
|
23
|
+
return "'#{label}' must be a step of #{@step}, the nearest valid values are #{@lower_step} and #{@higher_step}" unless step_correct?
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def number_correct?
|
29
|
+
return true if @value.blank?
|
30
|
+
return true if @value.match(/^\d*$/)
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def min_correct?
|
35
|
+
return true if @value.blank?
|
36
|
+
return true if @min.blank?
|
37
|
+
return true if @value.to_i >= @min.to_i
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def max_correct?
|
42
|
+
return true if @value.blank?
|
43
|
+
return true if @max.blank?
|
44
|
+
return true if @value.to_i <= @max.to_i
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
def step_correct?
|
49
|
+
return true if @value.blank?
|
50
|
+
return true if @step.blank?
|
51
|
+
start = @min.to_i || 0
|
52
|
+
step = @step.to_i
|
53
|
+
value = @value.to_i
|
54
|
+
match_mod = start % step
|
55
|
+
return true if value % step == match_mod
|
56
|
+
|
57
|
+
@lower_step = value - (value % step)
|
58
|
+
@higher_step = value + (step - (value % step))
|
59
|
+
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Formulary::HtmlForm::Labels
|
2
|
+
def label_for_field(field_name)
|
3
|
+
fields_for_name = document.css("*[name='#{field_name}']")
|
4
|
+
|
5
|
+
if fields_for_name.length > 1
|
6
|
+
labels_for_fieldset(fields_for_name)
|
7
|
+
else
|
8
|
+
label_for_single_field(fields_for_name.first)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def labels_for_fieldset(fields_for_name)
|
15
|
+
labels = fields_for_name.each_with_object({}) do |n, h|
|
16
|
+
h[n["value"]] = n.ancestors("label").first.text
|
17
|
+
end
|
18
|
+
|
19
|
+
fieldset_legend = fields_for_name.first.ancestors("fieldset").css("legend")
|
20
|
+
labels["fieldset"] = fieldset_legend.text
|
21
|
+
labels
|
22
|
+
end
|
23
|
+
|
24
|
+
def label_for_single_field(field)
|
25
|
+
input_id = field["id"]
|
26
|
+
label = document.css("label[for='#{input_id}']")
|
27
|
+
|
28
|
+
if label.empty?
|
29
|
+
parent_label = field.ancestors("label").first
|
30
|
+
if parent_label.nil?
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
parent_label.text.strip
|
34
|
+
end
|
35
|
+
else
|
36
|
+
label.text
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/formulary/version.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Formulary::HtmlForm::Fields::CheckboxGroup do
|
4
|
+
let(:markup_with_label) do
|
5
|
+
"<fieldset><legend>Field</legend>#{markup}</fieldset>"
|
6
|
+
end
|
7
|
+
let(:html_form) { Formulary::HtmlForm.new(markup_with_label) }
|
8
|
+
|
4
9
|
describe ".compatible_with?" do
|
5
10
|
subject { Formulary::HtmlForm::Fields::CheckboxGroup.compatible_with?(elements) }
|
6
11
|
|
@@ -40,14 +45,18 @@ describe Formulary::HtmlForm::Fields::CheckboxGroup do
|
|
40
45
|
|
41
46
|
describe "validations" do
|
42
47
|
subject(:checkbox_group) do
|
43
|
-
Formulary::HtmlForm::Fields::CheckboxGroup.new("
|
48
|
+
Formulary::HtmlForm::Fields::CheckboxGroup.new(html_form, "field", elements)
|
44
49
|
end
|
45
50
|
|
46
51
|
context "when one of the items in the group is required" do
|
47
52
|
let(:markup) do
|
48
53
|
%{
|
49
|
-
<
|
50
|
-
|
54
|
+
<label>
|
55
|
+
First<input type="checkbox" name="field" value="first" required>
|
56
|
+
</label>
|
57
|
+
<label>
|
58
|
+
Second<input type="checkbox" name="field" value="second">
|
59
|
+
</label>
|
51
60
|
}
|
52
61
|
end
|
53
62
|
|
@@ -69,27 +78,31 @@ describe Formulary::HtmlForm::Fields::CheckboxGroup do
|
|
69
78
|
before { checkbox_group.set_value("second") }
|
70
79
|
|
71
80
|
it { should_not be_valid }
|
72
|
-
its(:error) { should
|
81
|
+
its(:error) { should eql("'Field' is required") }
|
73
82
|
end
|
74
83
|
|
75
84
|
context "with a value that isn't expected" do
|
76
85
|
before { checkbox_group.set_value([ "first", "invalid" ]) }
|
77
86
|
|
78
87
|
it { should_not be_valid }
|
79
|
-
its(:error) { should
|
88
|
+
its(:error) { should eql("'Field' must be chosen from the available options") }
|
80
89
|
end
|
81
90
|
|
82
91
|
context "with no value" do
|
83
92
|
it { should_not be_valid }
|
84
|
-
its(:error) { should
|
93
|
+
its(:error) { should eql("'Field' is required") }
|
85
94
|
end
|
86
95
|
end
|
87
96
|
|
88
97
|
context "when none are required" do
|
89
98
|
let(:markup) do
|
90
99
|
%{
|
91
|
-
<
|
92
|
-
|
100
|
+
<label>
|
101
|
+
<input type="checkbox" name="field" value="first">
|
102
|
+
</label>
|
103
|
+
<label>
|
104
|
+
<input type="checkbox" name="field" value="second">
|
105
|
+
</label>
|
93
106
|
}
|
94
107
|
end
|
95
108
|
|
@@ -97,7 +110,7 @@ describe Formulary::HtmlForm::Fields::CheckboxGroup do
|
|
97
110
|
before { checkbox_group.set_value("invalid") }
|
98
111
|
|
99
112
|
it { should_not be_valid }
|
100
|
-
its(:error) { should
|
113
|
+
its(:error) { should eql("'Field' must be chosen from the available options") }
|
101
114
|
end
|
102
115
|
|
103
116
|
context "with no value" do
|
@@ -109,7 +122,7 @@ describe Formulary::HtmlForm::Fields::CheckboxGroup do
|
|
109
122
|
before { checkbox_group.set_value("on") }
|
110
123
|
|
111
124
|
it { should_not be_valid }
|
112
|
-
its(:error) { should
|
125
|
+
its(:error) { should eql("'Field' must be chosen from the available options") }
|
113
126
|
end
|
114
127
|
end
|
115
128
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::ColorInput do
|
4
|
+
let(:markup_with_label) { "<label for='field'>Field</label>#{markup}" }
|
5
|
+
let(:html_form) { Formulary::HtmlForm.new(markup_with_label) }
|
6
|
+
|
7
|
+
describe ".compatible_with?" do
|
8
|
+
subject { Formulary::HtmlForm::Fields::ColorInput.compatible_with?(element) }
|
9
|
+
let(:markup) { %{<input type="#{type}" name="name" />} }
|
10
|
+
|
11
|
+
context "color type" do
|
12
|
+
let(:type) { "color" }
|
13
|
+
it { should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "text type" do
|
17
|
+
let(:type) { "text" }
|
18
|
+
it { should be_false }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "validations" do
|
23
|
+
subject(:input) { Formulary::HtmlForm::Fields::ColorInput.new(html_form, element) }
|
24
|
+
let(:markup) { %{<input type="color" id="field" name="name" />} }
|
25
|
+
|
26
|
+
context "with a valid color" do
|
27
|
+
before { input.set_value("#123DEF") }
|
28
|
+
|
29
|
+
it { should be_valid }
|
30
|
+
its(:error) { should be_blank }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with an invalid color address" do
|
34
|
+
before { input.set_value("invalid!") }
|
35
|
+
|
36
|
+
it { should_not be_valid }
|
37
|
+
its(:error) { should eql("'Field' is not a valid color hex value") }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with a nil color" do
|
41
|
+
before { input.set_value(nil) }
|
42
|
+
|
43
|
+
it { should be_valid }
|
44
|
+
its(:error) { should be_blank }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it_should_behave_like "a field that allows the required attribute" do
|
49
|
+
let(:markup_with_required) { %{<input type="color" id="field" name="field" required />} }
|
50
|
+
let(:markup_without_required) { %{<input type="color" id="field" name="field" />} }
|
51
|
+
let(:valid_value) { "#123456" }
|
52
|
+
end
|
53
|
+
|
54
|
+
it_should_behave_like "a field that allows the pattern attribute" do
|
55
|
+
let(:markup) { %{<input type="color" id="field" name="field" pattern="^#[A-F]*$" />} }
|
56
|
+
let(:valid_value) { "#ABCDEF" }
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Formulary::HtmlForm::Fields::DateInput do
|
4
|
+
let(:markup_with_label) { "<label for='field'>Field</label>#{markup}" }
|
5
|
+
let(:html_form) { Formulary::HtmlForm.new(markup_with_label) }
|
6
|
+
|
7
|
+
describe ".compatible_with?" do
|
8
|
+
subject { Formulary::HtmlForm::Fields::DateInput.compatible_with?(element) }
|
9
|
+
let(:markup) { %{<input type="#{type}" name="name" />} }
|
10
|
+
|
11
|
+
context "text type" do
|
12
|
+
let(:type) { "text" }
|
13
|
+
it { should be_false }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "date type" do
|
17
|
+
let(:type) { "date" }
|
18
|
+
it { should be_true }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it_should_behave_like "a field that allows the required attribute" do
|
23
|
+
let(:markup_with_required) { %{<input type="date" id="field" name="field" required />} }
|
24
|
+
let(:markup_without_required) { %{<input type="date" id="field" name="field" />} }
|
25
|
+
let(:valid_value) { "2014-01-01" }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "validations" do
|
29
|
+
subject(:input) { Formulary::HtmlForm::Fields::DateInput.new(html_form, element) }
|
30
|
+
let(:markup) { %{<input type="date" id="field" name="test" min="2013-12-31" max="2014-02-01" />} }
|
31
|
+
|
32
|
+
context "with a valid date" do
|
33
|
+
before { input.set_value("2014-01-01") }
|
34
|
+
|
35
|
+
it { should be_valid }
|
36
|
+
its(:error) { should be_blank }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with a invalid date" do
|
40
|
+
before { input.set_value("1/5/14") }
|
41
|
+
|
42
|
+
it { should_not be_valid }
|
43
|
+
its(:error) { should eql("'Field' is not a properly formatted date, please use YYYY-MM-DD") }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with a date less than the min" do
|
47
|
+
before { input.set_value("2013-01-01") }
|
48
|
+
|
49
|
+
it { should_not be_valid }
|
50
|
+
its(:error) { should eql("'Field' must be a date after 2013-12-31") }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with a date greater than the max" do
|
54
|
+
before { input.set_value("2015-01-01") }
|
55
|
+
|
56
|
+
it { should_not be_valid }
|
57
|
+
its(:error) { should eql("'Field' must be a date before 2014-02-01") }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Formulary::HtmlForm::Fields::EmailInput do
|
4
|
+
let(:markup_with_label) { "<label for='field'>Field</label>#{markup}" }
|
5
|
+
let(:html_form) { Formulary::HtmlForm.new(markup_with_label) }
|
6
|
+
|
4
7
|
describe ".compatible_with?" do
|
5
8
|
subject { Formulary::HtmlForm::Fields::EmailInput.compatible_with?(element) }
|
6
9
|
let(:markup) { %{<input type="#{type}" name="name" />} }
|
@@ -17,19 +20,19 @@ describe Formulary::HtmlForm::Fields::EmailInput do
|
|
17
20
|
end
|
18
21
|
|
19
22
|
it_should_behave_like "a field that allows the required attribute" do
|
20
|
-
let(:markup_with_required) { %{<input type="email" name="field" required />} }
|
21
|
-
let(:markup_without_required) { %{<input type="email" name="field" />} }
|
23
|
+
let(:markup_with_required) { %{<input type="email" id="field" name="field" required />} }
|
24
|
+
let(:markup_without_required) { %{<input type="email" id="field" name="field" />} }
|
22
25
|
let(:valid_value) { "test@example.com" }
|
23
26
|
end
|
24
27
|
|
25
28
|
it_should_behave_like "a field that allows the pattern attribute" do
|
26
|
-
let(:markup) { '<input type="email" name="field" pattern="@example\.com$" />' }
|
29
|
+
let(:markup) { '<input type="email" id="field" name="field" pattern="@example\.com$" />' }
|
27
30
|
let(:valid_value) { "test@example.com" }
|
28
31
|
end
|
29
32
|
|
30
33
|
describe "validations" do
|
31
|
-
subject(:input) { Formulary::HtmlForm::Fields::EmailInput.new(element) }
|
32
|
-
let(:markup) { %{<input type="email" name="name" />} }
|
34
|
+
subject(:input) { Formulary::HtmlForm::Fields::EmailInput.new(html_form, element) }
|
35
|
+
let(:markup) { %{<input type="email" id="field" name="name" />} }
|
33
36
|
|
34
37
|
context "with a valid email address" do
|
35
38
|
before { input.set_value("test@example.com") }
|
@@ -42,7 +45,14 @@ describe Formulary::HtmlForm::Fields::EmailInput do
|
|
42
45
|
before { input.set_value("invalid!") }
|
43
46
|
|
44
47
|
it { should_not be_valid }
|
45
|
-
its(:error) { should
|
48
|
+
its(:error) { should eql("'Field' is not a valid email address") }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with an email address that is somewhat invalid but passes the client-side spec" do
|
52
|
+
before { input.set_value("e@e.e") }
|
53
|
+
|
54
|
+
it { should be_valid }
|
55
|
+
its(:error) { should be_blank }
|
46
56
|
end
|
47
57
|
|
48
58
|
context "with a nil email address" do
|