formal_wear 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.coveralls.yml CHANGED
@@ -1 +1 @@
1
- service_name: travis-pro
1
+ service_name: travis-ci
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
1
  --color
2
- --format documentation
2
+ --format progress
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # FormalWear
2
2
 
3
- [![Build Status](https://travis-ci.org/wideopenspaces/formal_wear.png)](https://travis-ci.org/wideopenspaces/formal_wear.png) [![Code Climate](https://codeclimate.com/github/wideopenspaces/formal_wear.png)](https://codeclimate.com/github/wideopenspaces/formal_wear) [![Coverage Status](https://coveralls.io/repos/wideopenspaces/formal_wear/badge.png)](https://coveralls.io/r/wideopenspaces/formal_wear)
3
+ [![Build Status](https://travis-ci.org/wideopenspaces/formal_wear.png)](https://travis-ci.org/wideopenspaces/formal_wear.png) [![Code Climate](https://codeclimate.com/github/wideopenspaces/formal_wear.png)](https://codeclimate.com/github/wideopenspaces/formal_wear) [![Coverage Status](https://coveralls.io/repos/wideopenspaces/formal_wear/badge.png)](https://coveralls.io/r/wideopenspaces/formal_wear) [![Dependency Status](https://gemnasium.com/wideopenspaces/formal_wear.png)](https://gemnasium.com/wideopenspaces/formal_wear)
4
4
 
5
5
  "You're going to like the way you look. I guarantee it."
6
6
 
@@ -22,7 +22,90 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+ class TestFormalWear
27
+ include FormalWear
28
+
29
+ required_attr moms_id: {
30
+ name: "Your mom's id",
31
+ type: :text,
32
+ source: ->(s) { s.primary.thing_to_be_configured },
33
+ }
34
+
35
+ required_attr docs_id: {
36
+ name: "Your doc's id",
37
+ type: :text,
38
+ source: ->(s) { s.primary.dependent_object.another_thing_to_be_configured },
39
+ store: :set_my_docs_id
40
+ }
41
+
42
+ required_attr lambda_lambda_lambda: {
43
+ name: 'Revenge Of The Nerds!',
44
+ type: :text,
45
+ source: ->(s) { s.get_pledged },
46
+ store: ->(s) { s.got_lambda? }
47
+ }
48
+
49
+ protected
50
+
51
+ def after_save
52
+ # no-op
53
+ end
54
+
55
+ def set_moms_id
56
+ # no-op
57
+ end
58
+
59
+ def set_my_docs_id
60
+ # no-op
61
+ end
62
+
63
+ def got_lambda?
64
+ # no-op
65
+ end
66
+
67
+ def get_pledged
68
+ primary.dependent_object.another_thing_to_be_configured
69
+ end
70
+ end
71
+ ```
72
+
73
+ Including FormalWear into your class adds a `required_attrs` and `required_attr` methods.
74
+ Specifying a required attr, like so:
75
+
76
+ ```ruby
77
+ required_attr lambda_lambda_lambda: {
78
+ name: 'Revenge Of The Nerds!',
79
+ type: :text,
80
+ source: ->(s) { s.get_pledged },
81
+ store: ->(s) { s.got_lambda? }
82
+ }
83
+ ```
84
+
85
+ adds the attribute to the list of required_fields, and populates it from the source specified
86
+ in its hash when your class is initialized.
87
+
88
+ ### Instantiating
89
+
90
+ ```ruby
91
+ TestFormalWear.new(primary_object)
92
+ ```
93
+
94
+ ... where primary object you will use to fetch values from their source. (TODO: add support for multiple sources)
95
+
96
+ ### Specifying sources
97
+
98
+ The source option takes a lambda that accepts `self` as its argument. This allows you to use a
99
+ method within your class to fetch the information needed from its source, or to directly fetch it
100
+ using the `primary` object set when you instantiated the class.
101
+
102
+ Source is a required attribute, but it can return nil if you feel so inclined. It's a bit like going commando
103
+ under that tuxedo, though.
104
+
105
+ ## TODO
106
+
107
+ * Update this readme
108
+ * (Maybe?) Add helper methods for providing data for working with forms
26
109
 
27
110
  ## Contributing
28
111
 
@@ -1,15 +1,5 @@
1
1
  module FormalWear
2
2
  module ClassMethods
3
- def required_attrs(attrs)
4
- validate_attrs!(attrs)
5
-
6
- required = class_variable_get(:@@required_fields) || {}
7
- class_variable_set(:@@required_fields, required.merge(attrs))
8
-
9
- create_accessors(attrs.keys)
10
- end
11
- def required_attr(a); required_attrs(a); end
12
-
13
3
  def create_accessors(keys)
14
4
  keys.each { |k| self.send(:attr_accessor, k) unless method_defined?(k) }
15
5
  end
@@ -17,8 +7,12 @@ module FormalWear
17
7
  def validate_attrs!(attrs)
18
8
  attrs.each do |a, opts|
19
9
  opts.assert_valid_keys(*ALLOWED_KEYS)
20
- opts.assert_required_keys(*REQUIRED_KEYS)
10
+ opts.assert_required_keys(*required_keys(opts))
21
11
  end
22
12
  end
13
+
14
+ def required_keys(opts)
15
+ opts[:type] == :select ? REQUIRED_KEYS + [:select_options] : REQUIRED_KEYS
16
+ end
23
17
  end
24
18
  end
@@ -3,22 +3,36 @@ module FormalWear
3
3
  ### THE NITTY GRITTY STARTS HERE
4
4
 
5
5
  # Start the configuration process
6
- def initialize(primary)
7
- @primary = primary
6
+ def initialize(options = {})
7
+ set_sources(options)
8
8
  update_sources
9
9
  end
10
10
 
11
11
  def required_attributes
12
- required_fields.dup.each do |field, options|
13
- options.slice!(:name, :type)
12
+ sanitize_and_fill_attributes(required_fields)
13
+ end
14
+
15
+ def optional_attributes
16
+ sanitize_and_fill_attributes(optional_fields)
17
+ end
18
+
19
+ def attributes
20
+ {}.tap do |h|
21
+ h.merge!(required_attributes: required_attributes) if required_attributes
22
+ h.merge!(optional_attributes: optional_attributes) if optional_attributes
14
23
  end
15
24
  end
25
+ alias_method :to_h, :attributes
16
26
 
17
27
  # Return the list of required fields for this configurator
18
28
  def required_fields
19
29
  @@required_fields
20
30
  end
21
31
 
32
+ def optional_fields
33
+ @@optional_fields
34
+ end
35
+
22
36
  def required_fields_without_custom_stores
23
37
  required_fields.reject { |f,o| custom_store?(o) }
24
38
  end
@@ -27,16 +41,10 @@ module FormalWear
27
41
  required_fields.select { |f,o| custom_store?(o) }
28
42
  end
29
43
 
30
- def to_h
31
- {}.merge(required_attributes: required_attributes).tap do |h|
32
- required_fields.keys.each { |k| h[k] = self.send(k) }
33
- end
34
- end
35
-
36
44
  def update(attrs)
37
- raise ArgumentError, "update requires a Hash"
45
+ raise ArgumentError, "update requires a Hash" unless attrs.is_a?(Hash)
38
46
  attrs.each do |field, value|
39
- self.send(:"#{field}=", value) if instance_method_defined?(field)
47
+ send(:"#{field}=", value) if respond_to?(field)
40
48
  end
41
49
  end
42
50
 
@@ -67,6 +75,26 @@ module FormalWear
67
75
  after_save
68
76
  end
69
77
 
78
+ def sanitize_and_fill_attributes(fields)
79
+ fields.deep_dup.each do |field, options|
80
+ fill_attributes!(field, options)
81
+ sanitize_attributes!(options)
82
+ end
83
+ end
84
+
85
+ def sanitize_attributes!(options)
86
+ options.slice!(:name, :type, :value, :values)
87
+ end
88
+
89
+ def fill_attributes!(field, options)
90
+ options[:value] = self.send(field)
91
+ populate_select_values(options) if options[:type] == :select
92
+ end
93
+
94
+ def populate_select_values(options)
95
+ options[:values] = options[:select_options].call(self)
96
+ end
97
+
70
98
  def set_field(field, options)
71
99
  custom_store?(options) ? set_via_custom_store(field, options) : self.send(:"set_#{field}")
72
100
  end
@@ -97,6 +125,27 @@ module FormalWear
97
125
  custom_store?(options) && options[:store].try(:lambda?)
98
126
  end
99
127
 
128
+ def set_sources(options)
129
+ set_primary(options) and return unless options.is_a?(Hash)
130
+ if options[:sources].present?
131
+ @sources = options[:sources]
132
+ set_source_readers
133
+ end
134
+ end
135
+
136
+ def set_primary(source)
137
+ @primary = source
138
+ end
139
+
140
+ def set_source_readers
141
+ @sources.each { |alt, obj| set_source_reader(alt, obj) }
142
+ end
143
+
144
+ def set_source_reader(alt, obj)
145
+ class_eval { attr_reader alt }
146
+ instance_variable_set(:"@#{alt}", obj)
147
+ end
148
+
100
149
  # When donning formal_wear, pre-populate from source if available
101
150
  def update_sources
102
151
  required_fields.each do |field, options|
@@ -0,0 +1,19 @@
1
+ module FormalWear
2
+ module Suit
3
+ def self.up(klass)
4
+ class << klass
5
+ [:optional, :required].each do |kind|
6
+ define_method :"#{kind}_attrs" do |attrs|
7
+ validate_attrs!(attrs)
8
+
9
+ var = class_variable_get(:"@@#{kind}_fields") || {}
10
+ class_variable_set(:"@@#{kind}_fields", var.merge(attrs))
11
+
12
+ create_accessors(attrs.keys)
13
+ end
14
+ alias :"#{kind}_attr" :"#{kind}_attrs"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module FormalWear
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/formal_wear.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'formal_wear/version'
2
2
  require 'formal_wear/class_methods'
3
3
  require 'formal_wear/instance_methods'
4
+ require 'formal_wear/suit'
4
5
  require 'hash_assertions'
5
6
  require 'active_support/core_ext'
6
7
  require 'active_support/concern'
@@ -17,6 +18,8 @@ module FormalWear
17
18
  include FormalWear::InstanceMethods
18
19
 
19
20
  attr_reader :primary
20
- cattr_reader :required_fields
21
+ cattr_reader :required_fields, :optional_fields
22
+
23
+ FormalWear::Suit.up(self)
21
24
  end
22
- end
25
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require_relative './support/bare_object'
3
+
4
+ describe BareObject do
5
+ let(:obj) { BareObject }
6
+
7
+ context 'including FormalWear' do
8
+ before { obj.send(:include, FormalWear) }
9
+
10
+ context 'when required_attr is invoked' do
11
+ before do
12
+ obj.class_eval do
13
+ required_attr dynamic_id: {
14
+ name: "Test",
15
+ type: :text,
16
+ source: ->(s) { nil },
17
+ }
18
+ end
19
+ end
20
+
21
+ it 'sets a class variable called @@required_fields' do
22
+ obj.class_variable_defined?(:@@required_fields).should be_true
23
+ end
24
+
25
+ it 'adds the given field to @@required_fields' do
26
+ obj.class_variable_get(:@@required_fields).keys.should include(:dynamic_id)
27
+ end
28
+
29
+ it 'adds a reader for the field' do
30
+ obj.method_defined?(:dynamic_id).should be_true
31
+ end
32
+
33
+ it 'adds a writer for the field' do
34
+ obj.method_defined?(:dynamic_id=).should be_true
35
+ end
36
+ end
37
+
38
+ context 'when optional_attr is invoked' do
39
+ before do
40
+ obj.class_eval do
41
+ optional_attr optional_id: {
42
+ name: "Test",
43
+ type: :text,
44
+ source: ->(s) { nil },
45
+ }
46
+ end
47
+ end
48
+
49
+ it 'sets a class variable called @@optional_attr' do
50
+ obj.class_variable_defined?(:@@optional_fields).should be_true
51
+ end
52
+
53
+ it 'adds the given field to @@optional_attr' do
54
+ obj.class_variable_get(:@@optional_fields).keys.should include(:optional_id)
55
+ end
56
+
57
+ it 'adds a reader for the field' do
58
+ obj.method_defined?(:optional_id).should be_true
59
+ end
60
+
61
+ it 'adds a writer for the field' do
62
+ obj.method_defined?(:optional_id=).should be_true
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require_relative './support/test_formal_wear'
3
+
4
+ describe 'a configurator with completed setup' do
5
+ let(:ready_primary) { ExternalObjectOne.new('Formal', 'Wear') }
6
+ let(:ready_config) { TestFormalWear.new(ready_primary) }
7
+
8
+ subject { ready_config }
9
+
10
+ context 'when initialized' do
11
+ describe '#moms_id' do
12
+ it 'is equal to ExternalObjectOne.thing_to_be_configured' do
13
+ subject.moms_id.should == subject.primary.thing_to_be_configured
14
+ end
15
+ end
16
+
17
+ describe '#docs_id' do
18
+ it 'is equal to ExternalObjectTwo.another_thing_to_be_configured' do
19
+ subject.docs_id.should == subject.primary.dependent_object.another_thing_to_be_configured
20
+ end
21
+ end
22
+
23
+ describe '#lambda_lambda_lambda' do
24
+ it 'equals ExternalObjectTwo.yet_another_thing_to_be_configured' do
25
+ subject.lambda_lambda_lambda = subject.primary.dependent_object.yet_another_thing_to_be_configured
26
+ end
27
+
28
+ it 'equals the method cited in its source attr' do
29
+ subject.lambda_lambda_lambda = subject.send(:get_pledged)
30
+ end
31
+ end
32
+
33
+ describe '#i_am_optional' do
34
+ it 'is defined' do
35
+ subject.respond_to?(:i_am_optional).should be_true
36
+ end
37
+
38
+ it 'is nil' do
39
+ subject.i_am_optional.should be_nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+ require_relative './support/test_formal_wear'
3
+
4
+ describe 'a new FormalWear-ing object' do
5
+ let(:primary) { ExternalObjectOne.new(nil, nil)}
6
+ let(:config) { TestFormalWear.new(primary) }
7
+
8
+ subject { config }
9
+
10
+ it 'has a required_fields method' do
11
+ subject.should respond_to(:required_fields)
12
+ end
13
+
14
+ describe '#required_fields' do
15
+ subject { config.required_fields }
16
+ it { should be_a(Hash) }
17
+
18
+ it "should mirror class's @@required_fields" do
19
+ subject.should == config.class.class_variable_get(:@@required_fields)
20
+ end
21
+
22
+ it 'contains the appropriate required fields' do
23
+ subject.keys.should =~ [:moms_id, :docs_id, :lambda_lambda_lambda]
24
+ end
25
+ end
26
+
27
+ describe '#optional_fields' do
28
+ subject { config.optional_fields }
29
+ it { should be_a(Hash) }
30
+
31
+ it "should mirror class's @@optional_fields" do
32
+ subject.should == config.class.class_variable_get(:@@optional_fields)
33
+ end
34
+
35
+ it 'contains the appropriate optional fields' do
36
+ subject.keys.should =~ [:i_am_optional]
37
+ end
38
+ end
39
+
40
+ it 'has a valid? method' do
41
+ subject.should respond_to(:valid?)
42
+ end
43
+
44
+ it 'has a getter method for each of the required fields' do
45
+ subject.required_fields.keys.each do |k|
46
+ subject.should respond_to(k)
47
+ end
48
+ end
49
+
50
+ it 'has a setter method for each of the required fields' do
51
+ subject.required_fields.keys.each do |k|
52
+ subject.should respond_to(:"#{k}=")
53
+ end
54
+ end
55
+
56
+ context 'when a required field has a "store" key' do
57
+ context 'that is a symbol' do
58
+ it 'responds to a method corresponding to that symbol' do
59
+ subject.should respond_to(subject.required_fields[:docs_id][:store])
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when a required field does not have a "store" key' do
65
+ it 'responds to a set_xxx method for each required field' do
66
+ config.required_fields_without_custom_stores.each do |field, options|
67
+ subject.should respond_to(:"set_#{field}")
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'when supplied with only one source object' do
73
+ let(:config) { TestFormalWear.new(ExternalObjectTwo.new(nil)) }
74
+
75
+ it 'sets an instance variable called primary containing the source' do
76
+ config.instance_variable_defined?(:@primary).should be_true
77
+ end
78
+
79
+ it 'allows access to the primary object correctly' do
80
+ config.primary.yet_another_thing_to_be_configured.should == 'Stuff'
81
+ end
82
+ end
83
+
84
+ context 'when supplied with a Hash of source objects' do
85
+ let(:config) { TestFormalWear.new(sources: {
86
+ object_two: ExternalObjectTwo.new("I am a secondary") } ) }
87
+
88
+ it 'sets an instance variable called sources containing the sources' do
89
+ config.instance_variable_defined?(:@sources).should be_true
90
+ end
91
+
92
+ it 'sets instance variables for each source object by name' do
93
+ config.instance_variable_defined?(:@object_two).should be_true
94
+ end
95
+
96
+ it 'sets a reader for each source object' do
97
+ config.respond_to?(:object_two).should be_true
98
+ end
99
+
100
+ it 'allows access to the source object correctly' do
101
+ config.object_two.another_thing_to_be_configured.should == "I am a secondary"
102
+ end
103
+ end
104
+
105
+ describe '#attributes' do
106
+ context 'given an object that contains required and optional attrs' do
107
+ it 'returns a hash containing appropriate keys' do
108
+ config.attributes.keys.should include(:required_attributes, :optional_attributes)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#required_attributes' do
114
+ it 'removes all options except name, type and value' do
115
+ config.required_attributes.each do |r,o|
116
+ o.should_not include([:source, :store, :select_options])
117
+ end
118
+ end
119
+
120
+ it 'adds value to the options' do
121
+ config.required_attributes.each do |r,o|
122
+ o.should include(:value)
123
+ end
124
+ end
125
+
126
+ context 'given type :text' do
127
+ it 'does not add values to the options' do
128
+ config.required_attributes.each do |r,o|
129
+ o.should_not include(:values)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '#optional_attributes' do
136
+ it 'removes all options except name, type and value' do
137
+ config.optional_attributes.each do |r,o|
138
+ o.should_not include([:source, :store, :select_options])
139
+ end
140
+ end
141
+
142
+ it 'adds value to the options' do
143
+ config.optional_attributes.each do |r,o|
144
+ o.should include(:value)
145
+ end
146
+ end
147
+ end
148
+
149
+ describe '#valid?' do
150
+ subject { config }
151
+
152
+ context 'when none of the required fields are set' do
153
+ before do
154
+ config.moms_id = nil
155
+ end
156
+
157
+ it 'returns false' do
158
+ config.valid?.should be_false
159
+ end
160
+ end
161
+
162
+ context 'when not all of the required fields are set' do
163
+ before do
164
+ config.moms_id = 'zztop'
165
+ end
166
+
167
+ it 'returns false' do
168
+ config.valid?.should be_false
169
+ end
170
+ end
171
+
172
+ context 'when all of the required fields are set' do
173
+ before do
174
+ config.moms_id = config.docs_id = config.lambda_lambda_lambda = '1'
175
+ end
176
+
177
+ it 'returns true' do
178
+ config.valid?.should be_true
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '#update' do
184
+ context 'given anything other than a hash' do
185
+ subject { config.update("Bob") }
186
+
187
+ it 'raises an ArgumentError' do
188
+ expect { subject }.to raise_error(ArgumentError, 'update requires a Hash' )
189
+ end
190
+ end
191
+
192
+ context 'given a hash of params' do
193
+ subject { config.update(docs_id: 1, nonexistent_id: 4) }
194
+ it 'does not raise an error' do
195
+ expect { subject }.to_not raise_error(ArgumentError)
196
+ end
197
+
198
+ it 'updates local attributes based on input' do
199
+ subject
200
+ config.docs_id.should == 1
201
+ end
202
+
203
+ it 'should ignore attributes that do not exist' do
204
+ subject
205
+ config.try(:nonexistent_id).should be_nil
206
+ end
207
+ end
208
+ end
209
+
210
+ describe '#save' do
211
+ subject { config }
212
+
213
+ context 'when not valid?' do
214
+ it 'returns false' do
215
+ subject.save.should be_false
216
+ end
217
+ end
218
+
219
+ context 'when valid?' do
220
+ before do
221
+ subject.moms_id = subject.docs_id = subject.lambda_lambda_lambda = '1'
222
+ subject.required_fields_without_custom_stores.keys.each do |k|
223
+ subject.expects("set_#{k}").returns(true)
224
+ end
225
+
226
+ subject.required_fields_with_custom_stores.each do |field, opt|
227
+ if opt[:store].is_a?(Symbol)
228
+ subject.expects(opt[:store]).returns(true)
229
+ subject.expects(:"set_#{field}").never
230
+ elsif opt[:store].try(:lambda?)
231
+ subject.expects(:got_lambda?).returns(true)
232
+ end
233
+ end
234
+
235
+ subject.expects(:after_save).returns(true)
236
+ end
237
+
238
+ it 'calls the set_xxx methods for each required field' do
239
+ subject.save
240
+ end
241
+
242
+ it 'calls #after_save' do
243
+ # condition met by expectation above
244
+ subject.save
245
+ end
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Class#required_attr method' do
4
+ context 'when given unallowed field options' do
5
+ it 'raises an ArgumentError' do
6
+ expect { require_relative('./support/forbidden_option_tester') }.to raise_error(ArgumentError, "Unknown key: extraneous")
7
+ end
8
+ end
9
+
10
+ context 'when missing required field options' do
11
+ it 'raises an ArgumentError' do
12
+ expect { require_relative('./support/missing_option_tester') }.to raise_error(ArgumentError, /Missing required key:/)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require_relative './support/bare_object'
3
+ require_relative './support/select_source'
4
+
5
+ describe BareObject do
6
+ let(:obj) { BareObject }
7
+
8
+ context 'including FormalWear' do
9
+ before { obj.send(:include, FormalWear) }
10
+
11
+ context 'when required_attr is invoked' do
12
+ context 'with a field of type :select' do
13
+ context 'without select_options specified' do
14
+ it 'should raise an error' do
15
+ expect {
16
+ obj.class_eval do
17
+ required_attr unselect_me: {
18
+ name: 'Broken select',
19
+ type: :select,
20
+ source: ->(s) { SelectSource.first },
21
+ }
22
+ end
23
+ }.to raise_error
24
+ end
25
+ end
26
+
27
+ context 'with select_options specified' do
28
+ before do
29
+ obj.class_eval do
30
+ required_attr select_me: {
31
+ name: "Selected",
32
+ type: :select,
33
+ source: ->(s) { SelectSource.first },
34
+ select_options: ->(s) { SelectSource.all }
35
+ }
36
+ end
37
+ end
38
+
39
+ context 'a new BareObject' do
40
+ subject { BareObject.new }
41
+ context '#required_attributes' do
42
+ it 'includes select_me' do
43
+ subject.required_attributes.keys.should include(:select_me)
44
+ end
45
+
46
+ context '[:select_me]' do
47
+ let(:new_obj) { BareObject.new }
48
+ let(:select_me) { new_obj.required_attributes[:select_me] }
49
+ subject { select_me }
50
+
51
+ it 'includes a values key' do
52
+ subject.keys.should include(:values)
53
+ end
54
+
55
+ context '[:values]' do
56
+ subject { select_me[:values] }
57
+ it 'contains the data specified in the select_options key' do
58
+ subject.should == SelectSource.all
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,2 @@
1
+ class BareObject
2
+ end
@@ -0,0 +1,10 @@
1
+ class ForbiddenOptionTester
2
+ include FormalWear
3
+
4
+ required_attr moms_id: {
5
+ name: "Your mom's id",
6
+ type: :text,
7
+ source: ->(s) { s.primary.thing_to_be_configured },
8
+ extraneous: :thing
9
+ }
10
+ end
@@ -0,0 +1,7 @@
1
+ class MissingOptionTester
2
+ include FormalWear
3
+
4
+ required_attr moms_id: {
5
+ name: "Your mom's id"
6
+ }
7
+ end
@@ -0,0 +1,13 @@
1
+ class SelectSource
2
+ def self.all
3
+ [
4
+ { id: 1, name: 'Option 1' },
5
+ { id: 2, name: 'Option 2' },
6
+ { id: 3, name: 'Option 3' }
7
+ ]
8
+ end
9
+
10
+ def self.first
11
+ all.first
12
+ end
13
+ end
@@ -23,6 +23,12 @@ class TestFormalWear
23
23
  store: ->(s) { s.got_lambda? }
24
24
  }
25
25
 
26
+ optional_attr i_am_optional: {
27
+ name: 'Test optional',
28
+ type: 'text',
29
+ source: ->(s) { nil }
30
+ }
31
+
26
32
  protected
27
33
 
28
34
  def after_save
@@ -42,7 +48,7 @@ class TestFormalWear
42
48
  end
43
49
 
44
50
  def get_pledged
45
- primary.dependent_object.another_thing_to_be_configured
51
+ primary.dependent_object.yet_another_thing_to_be_configured
46
52
  end
47
53
  end
48
54
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: formal_wear
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-03 00:00:00.000000000 Z
12
+ date: 2013-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -111,10 +111,19 @@ files:
111
111
  - lib/formal_wear.rb
112
112
  - lib/formal_wear/class_methods.rb
113
113
  - lib/formal_wear/instance_methods.rb
114
+ - lib/formal_wear/suit.rb
114
115
  - lib/formal_wear/version.rb
116
+ - spec/bare_object_spec.rb
117
+ - spec/completed_object_spec.rb
118
+ - spec/new_object_spec.rb
119
+ - spec/required_attr_spec.rb
120
+ - spec/select_source_spec.rb
115
121
  - spec/spec_helper.rb
116
- - spec/test_formal_wear.rb
117
- - spec/test_formal_wear_spec.rb
122
+ - spec/support/bare_object.rb
123
+ - spec/support/forbidden_option_tester.rb
124
+ - spec/support/missing_option_tester.rb
125
+ - spec/support/select_source.rb
126
+ - spec/support/test_formal_wear.rb
118
127
  homepage: https://github.com/wideopenspaces/formal_wear
119
128
  licenses: []
120
129
  post_install_message:
@@ -140,6 +149,14 @@ signing_key:
140
149
  specification_version: 3
141
150
  summary: You're going to like the way you look. I guarantee it.
142
151
  test_files:
152
+ - spec/bare_object_spec.rb
153
+ - spec/completed_object_spec.rb
154
+ - spec/new_object_spec.rb
155
+ - spec/required_attr_spec.rb
156
+ - spec/select_source_spec.rb
143
157
  - spec/spec_helper.rb
144
- - spec/test_formal_wear.rb
145
- - spec/test_formal_wear_spec.rb
158
+ - spec/support/bare_object.rb
159
+ - spec/support/forbidden_option_tester.rb
160
+ - spec/support/missing_option_tester.rb
161
+ - spec/support/select_source.rb
162
+ - spec/support/test_formal_wear.rb
@@ -1,151 +0,0 @@
1
- require 'spec_helper'
2
- require 'test_formal_wear'
3
-
4
- describe TestFormalWear do
5
- let(:primary) { ExternalObjectOne.new(nil, nil)}
6
- let(:config) { TestFormalWear.new(primary) }
7
-
8
- describe 'a configurator with completed setup' do
9
- let(:ready_primary) { ExternalObjectOne.new('Formal', 'Wear') }
10
- let(:ready_config) { TestFormalWear.new(ready_primary) }
11
-
12
- subject { ready_config }
13
-
14
- context 'when initialized' do
15
- describe '#moms_id' do
16
- it 'is equal to ExternalObjectOne.thing_to_be_configured' do
17
- subject.moms_id.should == subject.primary.thing_to_be_configured
18
- end
19
- end
20
-
21
- describe '#docs_id' do
22
- it 'is equal to ExternalObjectTwo.another_thing_to_be_configured' do
23
- subject.docs_id.should == subject.primary.dependent_object.another_thing_to_be_configured
24
- end
25
- end
26
- end
27
- end
28
-
29
- describe 'a new configurator object' do
30
- subject { config }
31
-
32
- it 'has a required_fields method' do
33
- subject.should respond_to(:required_fields)
34
- end
35
-
36
- describe '#required_fields' do
37
- subject { config.required_fields }
38
- it { should be_a(Hash) }
39
-
40
- it 'contains the appropriate required fields' do
41
- subject.keys.should =~ [:moms_id, :docs_id, :lambda_lambda_lambda]
42
- end
43
- end
44
-
45
- it 'has a valid? method' do
46
- subject.should respond_to(:valid?)
47
- end
48
-
49
- it 'has a getter method for each of the required fields' do
50
- subject.required_fields.keys.each do |k|
51
- subject.should respond_to(k)
52
- end
53
- end
54
-
55
- it 'has a setter method for each of the required fields' do
56
- subject.required_fields.keys.each do |k|
57
- subject.should respond_to(:"#{k}=")
58
- end
59
- end
60
-
61
- context 'when a required field has a "store" key' do
62
- context 'that is a symbol' do
63
- it 'responds to a method corresponding to that symbol' do
64
- subject.should respond_to(subject.required_fields[:docs_id][:store])
65
- end
66
- end
67
- end
68
-
69
- context 'when a required field does not have a "store" key' do
70
- it 'responds to a set_xxx method for each required field' do
71
- config.required_fields_without_custom_stores.each do |field, options|
72
- subject.should respond_to(:"set_#{field}")
73
- end
74
- end
75
- end
76
- end
77
-
78
- describe '#valid?' do
79
- subject { config }
80
-
81
- context 'when none of the required fields are set' do
82
- before do
83
- config.moms_id = nil
84
- end
85
-
86
- it 'returns false' do
87
- config.valid?.should be_false
88
- end
89
- end
90
-
91
- context 'when not all of the required fields are set' do
92
- before do
93
- config.moms_id = 'zztop'
94
- end
95
-
96
- it 'returns false' do
97
- config.valid?.should be_false
98
- end
99
- end
100
-
101
- context 'when all of the required fields are set' do
102
- before do
103
- config.moms_id = config.docs_id = config.lambda_lambda_lambda = '1'
104
- end
105
-
106
- it 'returns true' do
107
- config.valid?.should be_true
108
- end
109
- end
110
- end
111
-
112
- describe '#save' do
113
- subject { config }
114
-
115
- context 'when not valid?' do
116
- it 'returns false' do
117
- subject.save.should be_false
118
- end
119
- end
120
-
121
- context 'when valid?' do
122
- before do
123
- subject.moms_id = subject.docs_id = subject.lambda_lambda_lambda = '1'
124
- subject.required_fields_without_custom_stores.keys.each do |k|
125
- subject.expects("set_#{k}").returns(true)
126
- end
127
-
128
- subject.required_fields_with_custom_stores.each do |field, opt|
129
- if opt[:store].is_a?(Symbol)
130
- subject.expects(opt[:store]).returns(true)
131
- subject.expects(:"set_#{field}").never
132
- elsif opt[:store].try(:lambda?)
133
- subject.expects(:got_lambda?).returns(true)
134
- end
135
- end
136
-
137
- subject.expects(:after_save).returns(true)
138
- end
139
-
140
- it 'calls the set_xxx methods for each required field' do
141
- subject.save
142
- end
143
-
144
- it 'calls #after_save' do
145
- # condition met by expectation above
146
- subject.save
147
- end
148
- end
149
- end
150
-
151
- end