sexy_form 0.9.0

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.
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