instructions 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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