instructions 0.1.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 (45) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +26 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.textile +141 -0
  6. data/Rakefile +40 -0
  7. data/VERSION +1 -0
  8. data/extras/hint_errors.en.yml +27 -0
  9. data/init.rb +0 -0
  10. data/install.rb +1 -0
  11. data/instructions.gemspec +19 -0
  12. data/instructions.gemspec.generated +89 -0
  13. data/lib/core_files.rb +4 -0
  14. data/lib/instructions.rb +6 -0
  15. data/lib/instructions/abstract.rb +21 -0
  16. data/lib/instructions/attribute_state.rb +25 -0
  17. data/lib/instructions/configuration.rb +49 -0
  18. data/lib/instructions/core_ext/action_view_ext.rb +9 -0
  19. data/lib/instructions/error_message.rb +9 -0
  20. data/lib/instructions/error_message_tag.rb +21 -0
  21. data/lib/instructions/field_error.rb +33 -0
  22. data/lib/instructions/field_instructions.rb +6 -0
  23. data/lib/instructions/form_helper.rb +65 -0
  24. data/lib/instructions/formatters.rb +10 -0
  25. data/lib/instructions/instructions_tag.rb +15 -0
  26. data/lib/instructions/tag.rb +71 -0
  27. data/lib/instructions/valid_instructions_tag.rb +9 -0
  28. data/rails/init.rb +0 -0
  29. data/spec/attribute_state_spec.rb +62 -0
  30. data/spec/configuration_spec.rb +74 -0
  31. data/spec/error_message_spec.rb +42 -0
  32. data/spec/error_message_tag_spec.rb +30 -0
  33. data/spec/fake_model.rb +17 -0
  34. data/spec/field_error_spec.rb +85 -0
  35. data/spec/form_helper_spec.rb +123 -0
  36. data/spec/formatters_spec.rb +76 -0
  37. data/spec/spec_helper.rb +7 -0
  38. data/spec/support/field_instructions_namespace.rb +2 -0
  39. data/spec/support/html_safe_string.rb +7 -0
  40. data/spec/support/rspec_patches.rb +22 -0
  41. data/spec/tag_spec.rb +136 -0
  42. data/test/instructions_test.rb +8 -0
  43. data/test/test_helper.rb +3 -0
  44. data/uninstall.rb +1 -0
  45. metadata +110 -0
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe ErrorMessage do
4
+ before do
5
+ @model = Object.new
6
+ @model_errors = []
7
+ @model.stub :errors => @model_errors
8
+ @error_message_object = Object.new.extend ErrorMessage
9
+ set_model_errors
10
+ @error_message = @error_message_object.compose_error_message :some_attribute, @model
11
+ end
12
+
13
+ context "composing an error message for a field with many errors" do
14
+ def set_model_errors
15
+ @model_errors.stub :[] => ["some error message", "some other error message"]
16
+ end
17
+
18
+ observe "combines the many error messages into a single message" do
19
+ @error_message.should == "some error message, some other error message"
20
+ end
21
+ end
22
+
23
+ context "composing an error message for a field with one error" do
24
+ def set_model_errors
25
+ @model_errors.stub :[] => ["some error message"]
26
+ end
27
+
28
+ observe "reports the single error" do
29
+ @error_message.should == "some error message"
30
+ end
31
+ end
32
+
33
+ context "composing an error message for a field with no errors" do
34
+ def set_model_errors
35
+ @model_errors.stub :[] => []
36
+ end
37
+
38
+ observe "doesn't compose an error message" do
39
+ @error_message.should == ""
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe ErrorMessageTag do
4
+ context "building" do
5
+ because { ErrorMessageTag.build :some_attribute, @model, "some_model" }
6
+
7
+ observe "composes instructions from error messages" do
8
+ ErrorMessageTag.should_have_received :compose_error_message
9
+ end
10
+ end
11
+
12
+ context "rendering errors for a field that has no errors" do
13
+ before do
14
+ @model = Object.new
15
+
16
+ @human_attribute_name = "Some Attribute"
17
+ @model.class.stub :human_attribute_name => @human_attribute_name
18
+
19
+ @model_errors = []
20
+ @model.stub :errors => @model_errors
21
+ @model_errors.stub :[] => []
22
+
23
+ @tag = ErrorMessageTag.build :some_attribute, @model, "some_model"
24
+ end
25
+
26
+ observe "renders an empty error message" do
27
+ @tag.render.should include(">Some Attribute</")
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module FakeModel
2
+ def self.included(base)
3
+ base.class_eval do
4
+ before :each do
5
+ @model = Object.new
6
+ @model.stub :new_record? => false
7
+ @model.stub :some_attribute => "some attribute"
8
+
9
+ @human_attribute_name = "Some Attribute"
10
+ @model.class.stub :human_attribute_name => @human_attribute_name
11
+
12
+ @model_errors = []
13
+ @model.stub :errors => @model_errors
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe FieldError do
4
+ before do
5
+ @html_tag = "some html"
6
+
7
+ @model = "some model"
8
+ @model_errors = []
9
+ @attribute_errors = "some error message"
10
+
11
+ @model.stub :errors => @model_errors
12
+ @model_errors.stub :[] => @attribute_errors
13
+
14
+ @error_data = "some error data"
15
+ @error_data.stub :object => @model
16
+ @error_data.stub :object_name => "Model"
17
+
18
+ @attribute_name = "attribute"
19
+ @human_attribute_name = "Attribute"
20
+ @model.class.stub :human_attribute_name => @human_attribute_name
21
+
22
+ @error_data.stub :method_name => @attribute_name
23
+
24
+ @field_error = FieldError.new
25
+ end
26
+
27
+ context "rendering" do
28
+ before do
29
+ @html = FieldError.field_error_proc.call @html_tag, @error_data
30
+ end
31
+
32
+ observe "should render the field with the error wrapping" do
33
+ @html.should == '<div class="field_with_errors">some html</div>'
34
+ end
35
+ end
36
+
37
+ context "rendering" do
38
+ because { FieldError.render_field_with_error @html_tag, @error_data }
39
+
40
+ observe "wrap the html tag with a field with errors div" do
41
+ FieldError.should_have_received(:wrap_html_tag_with_field_with_errors_div)
42
+ end
43
+
44
+ observe "humanize the attribute name" do
45
+ @model.class.should_have_received(:human_attribute_name)
46
+ end
47
+ end
48
+
49
+ context "when rendering a div tag" do
50
+ before do
51
+ @html_tag = "<label>#{@html_tag}</label>"
52
+ end
53
+
54
+ because { FieldError.render_field_with_error @html_tag, @error_data }
55
+
56
+ observe "wrap the label tag with a model data with with errors div" do
57
+ FieldError.should_have_received(:wrap_label_tag_with_field_with_errors_label_div)
58
+ end
59
+
60
+ observe "doesn't render the error message" do
61
+ FieldError.should_not_have_received(:model_error_div)
62
+ end
63
+ end
64
+
65
+ context "when rendering the html tag with an error" do
66
+ before do
67
+ @html = FieldError.wrap_html_tag_with_field_with_errors_div @html_tag
68
+ end
69
+
70
+ observe "wrap the field with a field_with_errors div" do
71
+ @html.gsub(/some html/, '').should == '<div class="field_with_errors"></div>'
72
+ end
73
+ end
74
+
75
+ context "when rendering a label tag for a field with an error" do
76
+ before do
77
+ @html_tag = '<label>some model label</label>'
78
+ @html = FieldError.wrap_label_tag_with_field_with_errors_label_div @html_tag
79
+ end
80
+
81
+ observe "wrap the div with a model label with errors div" do
82
+ @html.gsub(/<label>some model label<\/label>/, '').should == '<div class="field_with_errors_label"></div>'
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,123 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'fake_model')
4
+
5
+ describe FormHelper do
6
+ include FakeModel
7
+
8
+ before do
9
+ @helper = Object.new.extend FormHelper
10
+ model = @model
11
+ @helper.instance_eval { @object = model }
12
+ end
13
+
14
+ context "rendering instructions" do
15
+ before do
16
+ @tag = Object.new.extend Tag
17
+ @tag.stub :render => nil
18
+
19
+ @helper.stub :renderer => @tag
20
+ end
21
+
22
+ because { @helper.instructions :some_attribute, "some_instructions" }
23
+
24
+ observe "determines the tag renderer to use" do
25
+ @helper.should_have_received(:renderer)
26
+ end
27
+
28
+ observe "renders instructions" do
29
+ @tag.should_have_received(:render)
30
+ end
31
+ end
32
+
33
+ context "rendering instructions" do
34
+ before do
35
+ @tag = Object.new.extend Tag
36
+ @tag.stub :render
37
+ @helper.stub :renderer => @tag
38
+ end
39
+
40
+ because { @helper.instructions :some_attribute, "some_instructions" }
41
+
42
+ observe "determines the tag renderer to use" do
43
+ @helper.should_have_received(:renderer)
44
+ end
45
+
46
+ observe "renders instructions" do
47
+ @tag.should_have_received(:render)
48
+ end
49
+ end
50
+
51
+ context "determining the renderer" do
52
+ before do
53
+ @helper.stub :determine
54
+ @helper.stub :merge
55
+ end
56
+
57
+ because { @tag = @helper.renderer :some_attribute, "can't be blank" }
58
+
59
+ it "determines the attribute state" do
60
+ @helper.should_have_received(:determine)
61
+ end
62
+
63
+ it "gets the formatters" do
64
+ @helper.should_have_received(:merge)
65
+ end
66
+ end
67
+
68
+ context FormHelper, "renderer" do
69
+ before do
70
+ @formatters = {:some_key => :some_value}
71
+ @helper.stub :merge => @formatters
72
+ end
73
+
74
+ context "for a new attribute" do
75
+ before do
76
+ @helper.stub :determine => :new
77
+ @tag = @helper.renderer :some_attribute, "can't be blank"
78
+ end
79
+
80
+ observe "uses the instructions tag" do
81
+ @tag.class.should == InstructionsTag
82
+ end
83
+
84
+ observe "configures tag with formatters" do
85
+ @tag.formatters.should == @formatters
86
+ end
87
+ end
88
+
89
+ context "for a valid attribute" do
90
+ before do
91
+ @helper.stub :determine => :valid
92
+ @tag = @helper.renderer :some_attribute, "can't be blank"
93
+ end
94
+
95
+ observe "uses the valid instructions tag" do
96
+ @tag.class.should == ValidInstructionsTag
97
+ end
98
+
99
+ observe "configures tag with formatters" do
100
+ @tag.formatters.should == @formatters
101
+ end
102
+ end
103
+
104
+ context "for an ininvalid attribute" do
105
+ before do
106
+ @model_errors.stub :[] => ["some error message"]
107
+
108
+ @helper.stub :determine => :invalid
109
+ @tag = @helper.renderer :some_attribute, "can't be blank"
110
+ end
111
+
112
+ observe "uses the error message tag" do
113
+ @tag.class.should == ErrorMessageTag
114
+ end
115
+
116
+ observe "configures tag with formatters" do
117
+ @tag.formatters.should == @formatters
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+
@@ -0,0 +1,76 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ module FormattersSetup
4
+ def self.included(base)
5
+ base.class_eval do
6
+ end
7
+ end
8
+ end
9
+
10
+ describe Formatters do
11
+ before do
12
+ @configured_formatters = {}
13
+ Configuration.stub :formatters => @configured_formatters
14
+ @formatters_object = Object.new.extend Formatters
15
+ end
16
+
17
+ context "merging local formatters over configured formatters" do
18
+ before do
19
+ @configured_formatters[:some_formattable] = :some_configured_formatter
20
+ @options = { :formatters => { :some_attribute_state => { :some_formattable => :tag_formatter }}}
21
+ @formatters = @formatters_object.merge :some_attribute_state, @options
22
+ end
23
+
24
+ observe "local formatters take precedence" do
25
+ @formatters[:some_formattable].should == :tag_formatter
26
+ end
27
+ end
28
+
29
+ context "merging when no configured formatters" do
30
+ before do
31
+ @configured_formatters[:some_formattable] = nil
32
+ @options = { :formatters => { :some_attribute_state => { :some_formattable => :tag_formatter }}}
33
+ @formatters = @formatters_object.merge :some_attribute_state, @options
34
+ end
35
+
36
+ observe "local formatters take precedence" do
37
+ @formatters[:some_formattable].should == :tag_formatter
38
+ end
39
+ end
40
+
41
+ context "merging when no configured formatter for the attribute state" do
42
+ before do
43
+ @configured_formatters[:some_other_formattable] = :some_configured_formatter
44
+ @options = { :formatters => { :some_attribute_state => { :some_formattable => :tag_formatter }}}
45
+ @formatters = @formatters_object.merge :some_attribute_state, @options
46
+ end
47
+
48
+ observe "local formatters take precedence" do
49
+ @formatters[:some_formattable].should == :tag_formatter
50
+ end
51
+ end
52
+
53
+ context "merging when there are no local formatters but there are configured formatters" do
54
+ before do
55
+ @configured_formatters[:some_formattable] = :some_configured_formatter
56
+ @options = {}
57
+ @formatters = @formatters_object.merge :some_attribute_state, @options
58
+ end
59
+
60
+ observe "configured formatters take precedence" do
61
+ @formatters[:some_formattable].should == :some_configured_formatter
62
+ end
63
+ end
64
+
65
+ context "merging when there are no local formatters for the attribute state but there are configured formatters" do
66
+ before do
67
+ @configured_formatters[:some_formattable] = :some_configured_formatter
68
+ @options = { :formatters => { :some_other_attribute_state => { :some_formattable => :tag_formatter }}}
69
+ @formatters = @formatters_object.merge :some_attribute_state, @options
70
+ end
71
+
72
+ observe "configured formatters take precedence" do
73
+ @formatters[:some_formattable].should == :some_configured_formatter
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,7 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
@@ -0,0 +1,2 @@
1
+ require 'core_files'
2
+ include Instructions
@@ -0,0 +1,7 @@
1
+ module HtmlSafeString
2
+ String.class_eval do
3
+ def html_safe
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ module RSpec
2
+ module Core
3
+ module Hooks
4
+ def because(*args, &block)
5
+ scope, options = scope_and_options_from(*args)
6
+ hooks[:after][scope] << AfterHook.new(options, &block)
7
+ end
8
+ end
9
+ end
10
+ module Mocks
11
+ module Methods
12
+ alias_method :should_have_received, :should_receive
13
+ alias_method :should_not_have_received, :should_not_receive
14
+ end
15
+ end
16
+ end
17
+
18
+ alias :context :describe
19
+
20
+ RSpec.configure do |config|
21
+ config.alias_example_to :observe
22
+ end
@@ -0,0 +1,136 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'spec_helper')
2
+
3
+ class TagClass
4
+ include Tag
5
+
6
+ def descriptor
7
+ "tag"
8
+ end
9
+
10
+ def css_class
11
+ "tag_class"
12
+ end
13
+ end
14
+
15
+ describe Tag do
16
+ include FakeModel
17
+
18
+ before do
19
+ @tag = TagClass.new :some_attribute, @model, "some_model", "some instructions"
20
+ end
21
+
22
+ context "rendering" do
23
+ before do
24
+ @tag.stub :open_tag => "some_tag_opening"
25
+ @tag.stub :instructions => "some_instructions"
26
+ @tag.stub :close_tag => "some_tag_closing"
27
+ end
28
+
29
+ because { @tag.render }
30
+
31
+ observe "opens the tag" do
32
+ @tag.should_have_received :open_tag
33
+ end
34
+
35
+ observe "composes the instructions" do
36
+ @tag.should_have_received :instructions
37
+ end
38
+
39
+ observe "closes the tag" do
40
+ @tag.should_have_received :close_tag
41
+ end
42
+ end
43
+
44
+ context "instructions are not provided" do
45
+ before do
46
+ @tag.instance_eval { @instructions = nil }
47
+ @tag.stub :formatted_attribute_name => nil
48
+ @tag.stub :formatted_instructions => nil
49
+
50
+ @tag.render
51
+ end
52
+
53
+ observe "doesn't compose the instructions" do
54
+ @tag.should_not_have_received :formatted_instructions
55
+ end
56
+
57
+ observe 'CSS class includes "empty"' do
58
+ @tag.formatted_css_class.should include "empty"
59
+ end
60
+ end
61
+
62
+ context "rendering the open tag" do
63
+ before do
64
+ @tag.stub :identifier => "some_html_id"
65
+ @tag.stub :css_class => "some_class"
66
+ end
67
+
68
+ because { @tag.render }
69
+
70
+ observe "composes the HTML ID" do
71
+ @tag.should_have_received(:identifier)
72
+ end
73
+
74
+ observe "composes the CSS class" do
75
+ @tag.should_have_received(:css_class)
76
+ end
77
+ end
78
+
79
+ context "composing the id for a model attribute" do
80
+ before do
81
+ @id = @tag.field_identifier
82
+ end
83
+
84
+ observe "is formatted as {model name}_{attribute_name}" do
85
+ @id.should == "some_model_some_attribute"
86
+ end
87
+ end
88
+
89
+ context "rendered content" do
90
+ before do
91
+ @rendered = @tag.render
92
+ end
93
+
94
+ observe "includes the attribute name" do
95
+ @rendered.should include(">Some Attribute")
96
+ end
97
+
98
+ observe "includes the instructions" do
99
+ @rendered.should include("some instructions<")
100
+ end
101
+
102
+ observe "includes the CSS class" do
103
+ @rendered.should include("class=\"tag_class\"")
104
+ end
105
+
106
+ observe "includes the HTML ID" do
107
+ @rendered.should include("id=\"some_model_some_attribute_tag\"")
108
+ end
109
+ end
110
+
111
+ context "rendering using an attribute name formatter" do
112
+ before do
113
+ @formatter = Proc.new { "some formatted name" }
114
+ formatters = {:attribute_name => @formatter}
115
+ tag = TagClass.new :some_attribute, @model, "some_model", "some instructions", formatters
116
+ @rendered = tag.render
117
+ end
118
+
119
+ observe "formats the attribute name" do
120
+ @rendered.should include(">some formatted name")
121
+ end
122
+ end
123
+
124
+ context "rendering using an instructions formatter" do
125
+ before do
126
+ @formatter = Proc.new {"some formatted instructions" }
127
+ formatters = {:instructions => @formatter}
128
+ tag = TagClass.new :some_attribute, @model, "some_model", "some instructions", formatters
129
+ @rendered = tag.render
130
+ end
131
+
132
+ observe "formats the instructions" do
133
+ @rendered.should include("some formatted instructions<")
134
+ end
135
+ end
136
+ end