smart_properties 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1ad423c03336ecabd1643f2cfea0faacc7e74f68
4
+ data.tar.gz: 5b1f77117faaa6314f0a4fe62952367cf3f13fcd
5
+ SHA512:
6
+ metadata.gz: cb13998cb8ca5404110a2596dbc58442a13554d75026d44668759a35b7c3a942de99b3c80f32465917e5e4ff3c7a414f194768dc78ceb49a8eea89901e14c905
7
+ data.tar.gz: 61d44649397e83afb2c1abb20af45c01e7aac716e73089720d210b5faeb798c6d6695cc627287c564cb9b41f642c1383e72a52df7bb656cea3c38ce7040dbbda
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SmartProperties
1
+ # Smartproperties
2
2
 
3
3
  Ruby accessors on steroids.
4
4
 
@@ -6,15 +6,21 @@ Ruby accessors on steroids.
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'smart_properties'
9
+ ```ruby
10
+ gem 'smart_properties'
11
+ ```
10
12
 
11
13
  And then execute:
12
14
 
13
- $ bundle
15
+ ```plain
16
+ $ bundle
17
+ ```
14
18
 
15
19
  Or install it yourself as:
16
20
 
17
- $ gem install smart_properties
21
+ ```plain
22
+ $ gem install smart_properties
23
+ ```
18
24
 
19
25
  ## Usage
20
26
 
@@ -45,32 +51,45 @@ The example below shows how to implement a class called `Message` which has
45
51
  three properties: `subject`, `body`, and `priority`. The two properties,
46
52
  `subject` and `priority`, are required whereas `body` is optional.
47
53
  Furthermore, all properties use input conversion. The `priority` property also
48
- uses validation and has a default value.
49
-
50
- class Message
51
- property :subject, :converts => :to_s
52
-
53
- property :body, :converts => :to_s
54
-
55
- property :priority, :converts => :to_sym,
56
- :accepts => [:low, :normal, :high],
57
- :default => :normal
58
- :required => true
59
- end
60
-
54
+ uses validation and has a default value so if it is not set during initialization
55
+ it will be set according to the default value.
56
+
57
+ ```ruby
58
+ require 'rubygems'
59
+ require 'smart_properties'
60
+
61
+ class Message
62
+ include SmartProperties
63
+
64
+ property :subject, :converts => :to_s,
65
+ :required => true
66
+
67
+ property :body, :converts => :to_s
68
+
69
+ property :priority, :converts => :to_sym,
70
+ :accepts => [:low, :normal, :high],
71
+ :default => :normal,
72
+ :required => true
73
+ end
74
+ ```
75
+
61
76
  Creating an instance of this class without specifying any attributes will
62
77
  result in an `ArgumentError` telling you to specify the required property
63
78
  `subject`.
64
79
 
65
- Message.new # => raises ArgumentError, "Message requires the property subject to be set"
80
+ ```ruby
81
+ Message.new # => raises ArgumentError, "Message requires the property subject to be set"
82
+ ```
66
83
 
67
84
  Providing the constructor with a title but with an invalid value for the
68
85
  property `priority` will also result in an `ArgumentError` telling you to
69
86
  provide a proper value for the property `priority`.
70
87
 
71
- m = Message.new :subject => 'Lorem ipsum'
72
- m.priority # => :normal
73
- m.priority = :urgent # => raises ArgumentError, Message does not accept :urgent as value for the property priority
88
+ ```ruby
89
+ m = Message.new :subject => 'Lorem ipsum'
90
+ m.priority # => :normal
91
+ m.priority = :urgent # => raises ArgumentError, Message does not accept :urgent as value for the property priority
92
+ ```
74
93
 
75
94
  Next, we discuss the various configuration options `SmartProperties` provide.
76
95
 
@@ -89,9 +108,11 @@ the result of this method call as value instead. The example below shows how
89
108
  to implement a property that automatically converts all given input to a
90
109
  `String` by calling `#to_s` on the object provided as input.
91
110
 
92
- class Article
93
- property :title, :converts => :to_s
94
- end
111
+ ```ruby
112
+ class Article
113
+ property :title, :converts => :to_s
114
+ end
115
+ ```
95
116
 
96
117
  If you need more fine-grained control, you can use a lambda statement to
97
118
  specify how the conversion should be done. The statement will be evaluated in
@@ -99,9 +120,11 @@ the context of the class defining the property and takes the given value as
99
120
  input. The example below shows how to implement a property that automatically
100
121
  converts all given input to a slug representation.
101
122
 
102
- class Article
103
- property :slug, :converts => lambda { |slug| slug.downcase.gsub(/\s+/, '-').gsub(/\W/, '') }
104
- end
123
+ ```ruby
124
+ class Article
125
+ property :slug, :converts => lambda { |slug| slug.downcase.gsub(/\s+/, '-').gsub(/\W/, '') }
126
+ end
127
+ ```
105
128
 
106
129
  #### Input validation
107
130
 
@@ -111,17 +134,21 @@ automatic validation whenever the setter for a certain property is called. The
111
134
  example below shows how to implement a property which only accepts instances
112
135
  of type `String` as input.
113
136
 
114
- class Article
115
- property :title, :accepts => String
116
- end
137
+ ```ruby
138
+ class Article
139
+ property :title, :accepts => String
140
+ end
141
+ ```
117
142
 
118
143
  Instead of using a class, you can also use a list of permitted values. The
119
144
  example below shows how to implement a property that only accepts `true` or
120
145
  `false` as values.
121
146
 
122
- class Article
123
- property :published, :accepts => [true, false]
124
- end
147
+ ```ruby
148
+ class Article
149
+ property :published, :accepts => [true, false]
150
+ end
151
+ ```
125
152
 
126
153
  You can also use a `lambda` statement for input validation if a more complex
127
154
  validation procedure is required. The `lambda` statement is evaluated in the
@@ -129,9 +156,11 @@ context of the class that defines the property and receives the given value as
129
156
  input. The example below shows how to implement a property called title that
130
157
  only accepts values which match the given regular expression.
131
158
 
132
- class Article
133
- property :title, :accepts => lambda { |title| /^Lorem \w+$/ =~ title }
134
- end
159
+ ```ruby
160
+ class Article
161
+ property :title, :accepts => lambda { |title| /^Lorem \w+$/ =~ title }
162
+ end
163
+ ```
135
164
 
136
165
  #### Default values
137
166
 
@@ -140,20 +169,39 @@ configuration parameter to configure a default value for a certain property.
140
169
  The example below demonstrates how to implement a property that has 42 as
141
170
  default value.
142
171
 
143
- class Article
144
- property :id, :default => 42
145
- end
172
+ ```ruby
173
+ class Article
174
+ property :id, :default => 42
175
+ end
176
+ ```
177
+
178
+ Default values can also be specified using blocks which are evaluated at
179
+ runtime.
146
180
 
147
181
  #### Presence checking
148
182
 
149
- To ensure that a property is always set set and never `nil`, you can use the
183
+ To ensure that a property is always set and never `nil`, you can use the
150
184
  `:required` configuration parameter. If present, this parameter will instruct
151
185
  the setter of a property to not accept nil as input. The example below shows
152
186
  how to implement a property that may not be `nil`.
153
187
 
154
- class Article
155
- property :title, :required => true
156
- end
188
+ ```ruby
189
+ class Article
190
+ property :title, :required => true
191
+ end
192
+ ```
193
+
194
+ The decision whether or not a property is required can also be delayed and
195
+ evaluated at runtime by providing a block instead of a boolean value. The
196
+ example below shows how to implement a class that has two properties, `name`
197
+ and `anonoymous`. The `name` is only required if `anonymous` is set to `false`.
198
+
199
+ ```ruby
200
+ class Person
201
+ property :name, required: lambda { not anonymous }
202
+ property :anonymous, required: true, default: true, accepts: [true, false]
203
+ end
204
+ ```
157
205
 
158
206
  ## Contributing
159
207
 
@@ -22,7 +22,7 @@
22
22
  #
23
23
  module SmartProperties
24
24
 
25
- VERSION = "1.2.3"
25
+ VERSION = "1.3.0"
26
26
 
27
27
  class Property
28
28
 
@@ -37,19 +37,15 @@ module SmartProperties
37
37
  @default = attrs.delete(:default)
38
38
  @converter = attrs.delete(:converts)
39
39
  @accepter = attrs.delete(:accepts)
40
- @required = !!attrs.delete(:required)
40
+ @required = attrs.delete(:required)
41
41
 
42
42
  unless attrs.empty?
43
43
  raise ArgumentError, "SmartProperties do not support the following configuration options: #{attrs.keys.map { |m| m.to_s }.sort.join(', ')}."
44
44
  end
45
45
  end
46
46
 
47
- def required=(value)
48
- @required = !!value
49
- end
50
-
51
- def required?
52
- @required
47
+ def required?(scope)
48
+ @required.kind_of?(Proc) ? scope.instance_exec(&@required) : !!@required
53
49
  end
54
50
 
55
51
  def convert(value, scope)
@@ -84,7 +80,7 @@ module SmartProperties
84
80
  end
85
81
 
86
82
  def prepare(value, scope)
87
- if required? && value.nil?
83
+ if required?(scope) && value.nil?
88
84
  raise ArgumentError, "#{scope.class.name} requires the property #{self.name} to be set"
89
85
  end
90
86
 
@@ -94,7 +90,7 @@ module SmartProperties
94
90
  raise ArgumentError, "#{scope.class.name} does not accept #{value.inspect} as value for the property #{self.name}"
95
91
  end
96
92
 
97
- @value = value
93
+ value
98
94
  end
99
95
 
100
96
  def define(klass)
@@ -259,7 +255,7 @@ module SmartProperties
259
255
  block.call(self) if block
260
256
 
261
257
  # Check presence of all required properties
262
- faulty_properties = properties.select { |_, property| property.required? && send(property.name).nil? }
258
+ faulty_properties = properties.select { |_, property| property.required?(self) && send(property.name).nil? }
263
259
  unless faulty_properties.empty?
264
260
  raise ArgumentError, "#{self.class.name} requires the following properties to be set: #{faulty_properties.map { |_, property| property.name }.sort.join(' ')}"
265
261
  end
@@ -11,7 +11,7 @@ describe SmartProperties do
11
11
  end
12
12
 
13
13
  it "should add a .property method" do
14
- subject.should respond_to(:property)
14
+ subject.respond_to?(:property, true).should be_true
15
15
  end
16
16
 
17
17
  context "and defining a property with invalid configuration options" do
@@ -620,6 +620,39 @@ describe SmartProperties do
620
620
 
621
621
  end
622
622
 
623
+ context "when building a class that has a property which is required depending on the value of another property" do
624
+
625
+ subject(:klass) do
626
+ described_class = self.described_class
627
+
628
+ Class.new do
629
+ include described_class
630
+ property :name, :required => lambda { not anonymous }
631
+ property :anonymous, accepts: [true, false], default: true
632
+ def self.name; "Dummy"; end
633
+ end
634
+ end
635
+
636
+ context "when created with no arguments" do
637
+ it "should not raise an error" do
638
+ expect { klass.new }.to_not raise_error
639
+ end
640
+ end
641
+
642
+ context "when created with no name and anonymous being set to false" do
643
+ it "should raise an error indicating that a required property was not specified" do
644
+ expect { klass.new anonymous: false }.to raise_error(ArgumentError, "Dummy requires the following properties to be set: name")
645
+ end
646
+ end
647
+
648
+ context "when created with a name and anonymous being set to false" do
649
+ it "should not raise an error" do
650
+ expect { klass.new name: "John Doe", anonymous: false }.to_not raise_error
651
+ end
652
+ end
653
+
654
+ end
655
+
623
656
  context "when building a class that has a property which is required and has false as default" do
624
657
 
625
658
  subject(:klass) do
metadata CHANGED
@@ -1,67 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_properties
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.2.3
4
+ version: 1.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Konstantin Tennhard
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-27 00:00:00.000000000 Z
11
+ date: 2013-08-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- type: :development
16
- version_requirements: !ruby/object:Gem::Requirement
17
- none: false
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
21
19
  version: '2.12'
22
- name: rspec
20
+ type: :development
23
21
  prerelease: false
24
- requirement: !ruby/object:Gem::Requirement
25
- none: false
22
+ version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
29
26
  version: '2.12'
30
27
  - !ruby/object:Gem::Dependency
31
- type: :development
32
- version_requirements: !ruby/object:Gem::Requirement
33
- none: false
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0.8'
38
- name: rake
34
+ type: :development
39
35
  prerelease: false
40
- requirement: !ruby/object:Gem::Requirement
41
- none: false
36
+ version_requirements: !ruby/object:Gem::Requirement
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0.8'
46
41
  - !ruby/object:Gem::Dependency
47
- type: :development
48
- version_requirements: !ruby/object:Gem::Requirement
49
- none: false
42
+ name: guard-rspec
43
+ requirement: !ruby/object:Gem::Requirement
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0.7'
54
- name: guard-rspec
48
+ type: :development
55
49
  prerelease: false
56
- requirement: !ruby/object:Gem::Requirement
57
- none: false
50
+ version_requirements: !ruby/object:Gem::Requirement
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0.7'
62
- description: ! " SmartProperties are a more flexible and feature-rich alternative
63
- to\n traditional Ruby accessors. They provide support for input conversion,\n input
64
- validation, specifying default values and presence checking.\n"
55
+ description: |2
56
+ SmartProperties are a more flexible and feature-rich alternative to
57
+ traditional Ruby accessors. They provide support for input conversion,
58
+ input validation, specifying default values and presence checking.
65
59
  email:
66
60
  - me@t6d.de
67
61
  executables: []
@@ -83,33 +77,26 @@ files:
83
77
  - spec/support/smart_property_matcher.rb
84
78
  homepage: ''
85
79
  licenses: []
80
+ metadata: {}
86
81
  post_install_message:
87
82
  rdoc_options: []
88
83
  require_paths:
89
84
  - lib
90
85
  required_ruby_version: !ruby/object:Gem::Requirement
91
- none: false
92
86
  requirements:
93
- - - ! '>='
87
+ - - '>='
94
88
  - !ruby/object:Gem::Version
95
- segments:
96
- - 0
97
- hash: -4042209003338815638
98
89
  version: '0'
99
90
  required_rubygems_version: !ruby/object:Gem::Requirement
100
- none: false
101
91
  requirements:
102
- - - ! '>='
92
+ - - '>='
103
93
  - !ruby/object:Gem::Version
104
- segments:
105
- - 0
106
- hash: -4042209003338815638
107
94
  version: '0'
108
95
  requirements: []
109
96
  rubyforge_project:
110
- rubygems_version: 1.8.24
97
+ rubygems_version: 2.0.6
111
98
  signing_key:
112
- specification_version: 3
99
+ specification_version: 4
113
100
  summary: SmartProperties – Ruby accessors on steroids
114
101
  test_files:
115
102
  - spec/smart_properties_spec.rb