sexy_form 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +21 -0
  4. data/README.md +275 -0
  5. data/Rakefile +15 -0
  6. data/lib/sexy_form.rb +84 -0
  7. data/lib/sexy_form/builder.rb +306 -0
  8. data/lib/sexy_form/themes.rb +22 -0
  9. data/lib/sexy_form/themes/base_theme.rb +39 -0
  10. data/lib/sexy_form/themes/bootstrap_2_horizontal.rb +83 -0
  11. data/lib/sexy_form/themes/bootstrap_2_inline.rb +73 -0
  12. data/lib/sexy_form/themes/bootstrap_2_vertical.rb +80 -0
  13. data/lib/sexy_form/themes/bootstrap_3_horizontal.rb +95 -0
  14. data/lib/sexy_form/themes/bootstrap_3_inline.rb +71 -0
  15. data/lib/sexy_form/themes/bootstrap_3_vertical.rb +70 -0
  16. data/lib/sexy_form/themes/bootstrap_4_horizontal.rb +95 -0
  17. data/lib/sexy_form/themes/bootstrap_4_inline.rb +80 -0
  18. data/lib/sexy_form/themes/bootstrap_4_vertical.rb +79 -0
  19. data/lib/sexy_form/themes/bulma_horizontal.rb +81 -0
  20. data/lib/sexy_form/themes/bulma_vertical.rb +73 -0
  21. data/lib/sexy_form/themes/default.rb +55 -0
  22. data/lib/sexy_form/themes/foundation.rb +67 -0
  23. data/lib/sexy_form/themes/materialize.rb +65 -0
  24. data/lib/sexy_form/themes/milligram.rb +62 -0
  25. data/lib/sexy_form/themes/semantic_ui_inline.rb +63 -0
  26. data/lib/sexy_form/themes/semantic_ui_vertical.rb +63 -0
  27. data/lib/sexy_form/version.rb +3 -0
  28. data/spec/custom_assertions.rb +21 -0
  29. data/spec/sexy_form/builder_spec.rb +104 -0
  30. data/spec/sexy_form/themes/base_theme_spec.rb +16 -0
  31. data/spec/sexy_form/themes/bootstrap_2_horizontal_spec.rb +114 -0
  32. data/spec/sexy_form/themes/bootstrap_2_inline_spec.rb +108 -0
  33. data/spec/sexy_form/themes/bootstrap_2_vertical_spec.rb +111 -0
  34. data/spec/sexy_form/themes/bootstrap_3_horizontal_spec.rb +116 -0
  35. data/spec/sexy_form/themes/bootstrap_3_inline_spec.rb +104 -0
  36. data/spec/sexy_form/themes/bootstrap_3_vertical_spec.rb +122 -0
  37. data/spec/sexy_form/themes/bootstrap_4_horizontal_spec.rb +124 -0
  38. data/spec/sexy_form/themes/bootstrap_4_inline_spec.rb +116 -0
  39. data/spec/sexy_form/themes/bootstrap_4_vertical_spec.rb +114 -0
  40. data/spec/sexy_form/themes/bulma_horizontal_spec.rb +126 -0
  41. data/spec/sexy_form/themes/bulma_vertical_spec.rb +114 -0
  42. data/spec/sexy_form/themes/default_spec.rb +102 -0
  43. data/spec/sexy_form/themes/foundation_spec.rb +103 -0
  44. data/spec/sexy_form/themes/materialize_spec.rb +103 -0
  45. data/spec/sexy_form/themes/milligram_spec.rb +120 -0
  46. data/spec/sexy_form/themes/semantic_ui_inline_spec.rb +105 -0
  47. data/spec/sexy_form/themes/semantic_ui_vertical_spec.rb +105 -0
  48. data/spec/sexy_form/themes/theme_spec_helper.rb +0 -0
  49. data/spec/sexy_form/themes_spec.rb +52 -0
  50. data/spec/sexy_form_spec.rb +54 -0
  51. data/spec/spec_helper.rb +16 -0
  52. metadata +160 -0
@@ -0,0 +1,55 @@
1
+ module SexyForm
2
+ module Themes
3
+ class Default < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
9
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
10
+
11
+ if ["checkbox", "radio"].include?(field_type) && html_label
12
+ s << html_label.sub("\">", "\">#{html_field} ")
13
+ else
14
+ s << html_label.to_s
15
+ s << html_field.to_s
16
+ end
17
+ s << html_help_text.to_s
18
+ s << html_errors.join if html_errors
19
+
20
+ s << "</div>"
21
+
22
+ s
23
+ end
24
+
25
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
26
+ html_attrs
27
+ end
28
+
29
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
30
+ html_attrs
31
+ end
32
+
33
+ def form_html_attributes(html_attrs:)
34
+ html_attrs
35
+ end
36
+
37
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
38
+ s = ""
39
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
40
+ s << "#{help_text}"
41
+ s << "</div>"
42
+ s
43
+ end
44
+
45
+ def build_html_error(error:, html_attrs:, field_type:)
46
+ s = ""
47
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
48
+ s << "#{error}"
49
+ s << "</div>"
50
+ s
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,67 @@
1
+ module SexyForm
2
+ module Themes
3
+ class Foundation < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
9
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
10
+
11
+ if !["checkbox", "radio"].include?(field_type) && html_label
12
+ s << html_label.sub("</label>", "#{html_field}</label>")
13
+ else
14
+ s << "#{html_field}"
15
+ s << "#{html_label}"
16
+ end
17
+ s << "#{html_help_text}"
18
+ s << html_errors.join if html_errors
19
+
20
+ s << "</div>"
21
+
22
+ s
23
+ end
24
+
25
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
26
+ if has_errors
27
+ html_attrs["class"] = "is-invalid-input #{html_attrs["class"]}".strip
28
+ end
29
+
30
+ html_attrs
31
+ end
32
+
33
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
34
+ if has_errors
35
+ html_attrs["class"] = "is-invalid-label #{html_attrs["class"]}".strip
36
+ end
37
+
38
+ html_attrs
39
+ end
40
+
41
+ def form_html_attributes(html_attrs:)
42
+ html_attrs
43
+ end
44
+
45
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
46
+ html_attrs["class"] = "help-text #{html_attrs["class"]}".strip
47
+
48
+ s = ""
49
+ s << (html_attrs.empty? ? "<p>" : "<p #{SexyForm.build_html_attr_string(html_attrs)}>")
50
+ s << "#{help_text}"
51
+ s << "</p>"
52
+ s
53
+ end
54
+
55
+ def build_html_error(error:, html_attrs:, field_type:)
56
+ html_attrs["class"] = "form-error #{html_attrs["class"]}".strip
57
+
58
+ s = ""
59
+ s << (html_attrs.empty? ? "<span>" : "<span #{SexyForm.build_html_attr_string(html_attrs)}>")
60
+ s << "#{error}"
61
+ s << "</span>"
62
+ s
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,65 @@
1
+ module SexyForm
2
+ module Themes
3
+ class Materialize < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ wrapper_html_attributes["class"] = "input-field #{wrapper_html_attributes["class"]}".strip
9
+
10
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
11
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
12
+
13
+ if ["checkbox", "radio"].include?(field_type) && html_label
14
+ s << html_label.sub("\">", "\">#{html_field}<span>").sub("</label>", "</span></label>")
15
+ else
16
+ s << "#{html_field}"
17
+ s << "#{html_label}"
18
+ end
19
+ s << "#{html_help_text}"
20
+ s << html_errors.join if html_errors
21
+
22
+ s << "</div>"
23
+
24
+ s
25
+ end
26
+
27
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
28
+ if has_errors
29
+ html_attrs["class"] = "invalid #{html_attrs["class"]}".strip
30
+ end
31
+
32
+ html_attrs
33
+ end
34
+
35
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
36
+ html_attrs
37
+ end
38
+
39
+ def form_html_attributes(html_attrs:)
40
+ html_attrs
41
+ end
42
+
43
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
44
+ html_attrs["class"] = "helper-text #{html_attrs["class"]}".strip
45
+
46
+ s = ""
47
+ s << (html_attrs.empty? ? "<span>" : "<span #{SexyForm.build_html_attr_string(html_attrs)}>")
48
+ s << "#{help_text}"
49
+ s << "</span>"
50
+ s
51
+ end
52
+
53
+ def build_html_error(error:, html_attrs:, field_type:)
54
+ html_attrs["class"] = "helper-text #{html_attrs["class"]}".strip
55
+
56
+ s = ""
57
+ s << (html_attrs.empty? ? "<span>" : "<span #{SexyForm.build_html_attr_string(html_attrs)}>")
58
+ s << "#{error}"
59
+ s << "</span>"
60
+ s
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,62 @@
1
+ module SexyForm
2
+ module Themes
3
+ class Milligram < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
9
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
10
+
11
+ if ["checkbox", "radio"].include?(field_type)
12
+ s << "#{html_field}"
13
+ s << "#{html_label}"
14
+ else
15
+ s << "#{html_label}"
16
+ s << "#{html_field}"
17
+ end
18
+ s << "#{html_help_text}"
19
+ s << html_errors.join if html_errors
20
+
21
+ s << "</div>"
22
+
23
+ s
24
+ end
25
+
26
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
27
+ html_attrs
28
+ end
29
+
30
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
31
+ if ["checkbox", "radio"].include?(field_type)
32
+ html_attrs["class"] = "label-inline #{html_attrs["class"]}".strip
33
+ end
34
+
35
+ html_attrs
36
+ end
37
+
38
+ def form_html_attributes(html_attrs:)
39
+ html_attrs
40
+ end
41
+
42
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
43
+ s = ""
44
+ s << (html_attrs.empty? ? "<small>" : "<small #{SexyForm.build_html_attr_string(html_attrs)}>")
45
+ s << "#{help_text}"
46
+ s << "</small>"
47
+ s
48
+ end
49
+
50
+ def build_html_error(error:, html_attrs:, field_type:)
51
+ html_attrs["style"] = "color: red; #{html_attrs["style"]}".strip
52
+
53
+ s = ""
54
+ s << (html_attrs.empty? ? "<small>" : "<small #{SexyForm.build_html_attr_string(html_attrs)}>")
55
+ s << "#{error}"
56
+ s << "</small>"
57
+ s
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,63 @@
1
+ module SexyForm
2
+ module Themes
3
+ class SemanticUIInline < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ wrapper_html_attributes["class"] = "inline field#{" error" if html_errors} #{wrapper_html_attributes["class"]}".strip
9
+
10
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
11
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
12
+
13
+ if ["checkbox", "radio"].include?(field_type)
14
+ s << %Q(<div class="ui checkbox#{" radio" if field_type == "radio"}">)
15
+ s << "#{html_field}"
16
+ s << "#{html_label}"
17
+ s << "</div>"
18
+ else
19
+ s << "#{html_label}"
20
+ s << "#{html_field}"
21
+ end
22
+ s << "#{html_help_text}"
23
+ s << html_errors.join if html_errors
24
+
25
+ s << "</div>"
26
+
27
+ s
28
+ end
29
+
30
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
31
+ html_attrs
32
+ end
33
+
34
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
35
+ html_attrs
36
+ end
37
+
38
+ def form_html_attributes(html_attrs:)
39
+ html_attrs["class"] = "ui form #{html_attrs["class"]}".strip
40
+ html_attrs
41
+ end
42
+
43
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
44
+ s = ""
45
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
46
+ s << "#{help_text}"
47
+ s << "</div>"
48
+ s
49
+ end
50
+
51
+ def build_html_error(error:, html_attrs:, field_type:)
52
+ html_attrs["style"] = "color: red; #{html_attrs["style"]}".strip
53
+
54
+ s = ""
55
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
56
+ s << "#{error}"
57
+ s << "</div>"
58
+ s
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,63 @@
1
+ module SexyForm
2
+ module Themes
3
+ class SemanticUIVertical < BaseTheme
4
+
5
+ def wrap_field(field_type:, html_field:, html_label:, html_help_text: nil, html_errors: nil, wrapper_html_attributes:)
6
+ s = ""
7
+
8
+ wrapper_html_attributes["class"] = "field#{" error" if html_errors} #{wrapper_html_attributes["class"]}".strip
9
+
10
+ attr_str = SexyForm.build_html_attr_string(wrapper_html_attributes)
11
+ s << "#{attr_str.empty? ? "<div>" : "<div #{attr_str}>"}"
12
+
13
+ if ["checkbox", "radio"].include?(field_type)
14
+ s << %Q(<div class="ui checkbox#{" radio" if field_type == "radio"}">)
15
+ s << "#{html_field}"
16
+ s << "#{html_label}"
17
+ s << "</div>"
18
+ else
19
+ s << "#{html_label}"
20
+ s << "#{html_field}"
21
+ end
22
+ s << "#{html_help_text}"
23
+ s << html_errors.join if html_errors
24
+
25
+ s << "</div>"
26
+
27
+ s
28
+ end
29
+
30
+ def input_html_attributes(html_attrs:, field_type:, has_errors:)
31
+ html_attrs
32
+ end
33
+
34
+ def label_html_attributes(html_attrs:, field_type:, has_errors:)
35
+ html_attrs
36
+ end
37
+
38
+ def form_html_attributes(html_attrs:)
39
+ html_attrs["class"] = "ui form #{html_attrs["class"]}".strip
40
+ html_attrs
41
+ end
42
+
43
+ def build_html_help_text(help_text:, html_attrs:, field_type:)
44
+ s = ""
45
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
46
+ s << "#{help_text}"
47
+ s << "</div>"
48
+ s
49
+ end
50
+
51
+ def build_html_error(error:, html_attrs:, field_type:)
52
+ html_attrs["style"] = "color: red; #{html_attrs["style"]}".strip
53
+
54
+ s = ""
55
+ s << (html_attrs.empty? ? "<div>" : "<div #{SexyForm.build_html_attr_string(html_attrs)}>")
56
+ s << "#{error}"
57
+ s << "</div>"
58
+ s
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module SexyForm
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,21 @@
1
+ def assert_changed(expression, &block)
2
+ if expression.respond_to?(:call)
3
+ e = expression
4
+ else
5
+ e = lambda{ eval(expression, block.binding) }
6
+ end
7
+ old = e.call
8
+ block.call
9
+ assert_not_equal old, e.call
10
+ end
11
+
12
+ def assert_not_changed(expression, &block)
13
+ if expression.respond_to?(:call)
14
+ e = expression
15
+ else
16
+ e = lambda{ eval(expression, block.binding) }
17
+ end
18
+ old = e.call
19
+ block.call
20
+ assert_equal old, e.call
21
+ end
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+
3
+ builder = SexyForm::Builder.new
4
+
5
+ describe SexyForm::Builder do
6
+
7
+ describe "#initialize" do
8
+ it "defaults to theme: :default" do
9
+ builder.theme.class.should eq(SexyForm::Themes::Default)
10
+ end
11
+
12
+ it "allows string :theme name" do
13
+ SexyForm::Builder.new(theme: "bootstrap_4_inline").theme.class.should eq(SexyForm::Themes::Bootstrap4Inline)
14
+ end
15
+
16
+ it "allows class instance :theme" do
17
+ expected = SexyForm::Themes::Bootstrap4Inline
18
+ SexyForm::Builder.new(theme: expected.new).theme.class.should eq(expected)
19
+ end
20
+ end
21
+
22
+ describe "#<<" do
23
+ it "supports its own string interpolation" do
24
+ (builder << "foo").should eq("foo")
25
+ (builder << "--").should eq("--")
26
+ (builder << "bar").should eq("bar")
27
+
28
+ builder.html_string.should eq("foo--bar")
29
+ end
30
+ end
31
+
32
+ describe "#field" do
33
+ it "does not allow incorrect types" do
34
+ expect {
35
+ builder.field(type: "submit", name: :foobar)
36
+ }.to raise_exception(ArgumentError)
37
+ end
38
+
39
+ describe "input fields" do
40
+ SexyForm::Builder::INPUT_TYPES.each do |field_type|
41
+
42
+ it "works for type: #{field_type}" do
43
+ expected = "<div><input type=\"#{field_type}\" foo=\"bar\" name=\"my-great-text-input\" id=\"my-great-text-input\"></div>"
44
+
45
+ builder.field(type: field_type, label: false, name: "my-great-text-input", input_html: {foo: :bar}).should eq(expected)
46
+ end
47
+
48
+ it "does not allow collection option" do
49
+ expect {
50
+ builder.field(type: field_type, label: false, name: "my-great-text-input", input_html: {foo: :bar}, collection: {options: ["foo", "bar"]})
51
+ }.to raise_exception(ArgumentError)
52
+ end
53
+
54
+ end
55
+ end
56
+
57
+ describe "select fields" do
58
+ it "works for select fields" do
59
+ expected = "<div><select foo=\"bar\" name=\"my-great-text-input\" id=\"my-great-text-input\"><option value=\"foo\">foo</option><option value=\"bar\">bar</option></select></div>"
60
+
61
+ builder.field(type: :select, label: false, name: "my-great-text-input", input_html: {foo: :bar}, collection: {options: ["foo", "bar"]}).should eq(expected)
62
+ end
63
+
64
+ describe "collection argument" do
65
+ it "is required" do
66
+ expect {
67
+ builder.field(type: :select, label: false, name: "my-great-text-input", input_html: {foo: :bar})
68
+ }.to raise_exception(ArgumentError)
69
+ end
70
+
71
+ it "all supported keys work" do
72
+ builder.field(type: :select, collection: {options: ["foo", "bar", "foobar"], selected: ["bar"], disabled: ["foobar"], include_blank: "blank"})
73
+
74
+ builder.field(type: :select, collection: {options: ["foo", "bar", "foobar"], selected: "bar", disabled: "foobar", include_blank: true})
75
+
76
+ builder.field(type: :select, collection: {options: "foobar"})
77
+ end
78
+
79
+ it "fails correctly" do
80
+ expect {
81
+ builder.field(type: :select, collection: {selected: "bar"})
82
+ }.to raise_exception(ArgumentError)
83
+
84
+ expect {
85
+ builder.field(type: :select, collection: {options: ["foo", "bar", "foobar"], foobar: "exception"})
86
+ }.to raise_exception(ArgumentError)
87
+
88
+ expect {
89
+ builder.field(type: :select, collection: {options: "foobar", selected: "asd"})
90
+ }.to raise_exception(ArgumentError)
91
+
92
+ expect {
93
+ builder.field(type: :select, collection: {options: "foobar", disabled: "asd"})
94
+ }.to raise_exception(ArgumentError)
95
+
96
+ expect {
97
+ builder.field(type: :select, collection: {options: "foobar", include_blank: "asd"})
98
+ }.to raise_exception(ArgumentError)
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ end