model_attribute 2.0.0 → 2.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.
- checksums.yaml +8 -8
- data/.travis.yml +5 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +0 -1
- data/Guardfile +1 -1
- data/README.md +27 -1
- data/Rakefile +8 -1
- data/lib/model_attribute.rb +18 -57
- data/lib/model_attribute/casts.rb +74 -0
- data/lib/model_attribute/version.rb +1 -1
- data/model_attribute.gemspec +4 -1
- data/spec/model_attributes_spec.rb +58 -21
- data/spec/spec_helper.rb +0 -1
- metadata +6 -18
- data/lib/model_attribute/json.rb +0 -27
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
ZjQzN2Q4YWFiMzRhYTA1NTI0Y2RkNDNjOGZlZjg4Zjk3ZTU1NzlkMQ==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
ZTc1NmViMDUxNDhiNmIzMGJiYmNiMzE5ZWM2ZDFjMGVmM2EwNjQxNg==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
MzM1MDY3M2Q0ZDE4MWViNjcwNjY4ZjI5OTg1ZjJkYjY5N2JlNWM2MmQyMTUx
|
|
10
|
+
ODRjZWVmNDI2NzIxODk4MmY0YmQ0MTY3NGM0OTk5OGExMTFjY2UwM2Q0MzQ2
|
|
11
|
+
MzMyY2FlM2M3ZDk5Zjc3YjUzYTY5NmIwNjQ3NjU1NjYxYjMyMWM=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
MmE3NmY2MmMyYmU3MmRiNzY5ZGRhNjQ3MzYxMDhlMzdiZjhlZTFiMDVhOTY3
|
|
14
|
+
MDU0M2Q1OGJjZjRkZGM5YjA3ZGYyY2E0OTBkNDUwMDAxM2Y1NmQ2MTUzOWZi
|
|
15
|
+
N2VkMmM5MzViMGQ3OWYyODljNTg3Y2E4ZGExZTVhMmQzMzgzODc=
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 2.1.0
|
|
6
|
+
|
|
7
|
+
- **New feature**: default values. Allows you to specify a default value like
|
|
8
|
+
so:
|
|
9
|
+
```
|
|
10
|
+
class User
|
|
11
|
+
attribute :name, :string, default: 'Michelle'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
User.new.name
|
|
15
|
+
# => 'Michelle'
|
|
16
|
+
```
|
|
17
|
+
|
|
5
18
|
## 2.0.0
|
|
6
19
|
|
|
7
20
|
- **Breaking change**: Rename to `ModelAttribute` (no trailing 's') to avoid name
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
|
@@ -29,7 +29,7 @@ watch ("Guardfile") do
|
|
|
29
29
|
exit 0
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
guard :rspec, cmd: "bundle exec rspec --format=Nc --format=documentation" do
|
|
32
|
+
guard :rspec, cmd: "bundle exec rspec --format=Nc --format=documentation", all_on_start: true do
|
|
33
33
|
require "guard/rspec/dsl"
|
|
34
34
|
dsl = Guard::RSpec::Dsl.new(self)
|
|
35
35
|
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ModelAttribute
|
|
1
|
+
# ModelAttribute [](https://travis-ci.org/yammer/model_attribute)
|
|
2
2
|
|
|
3
3
|
Simple attributes for a non-ActiveRecord model.
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ Simple attributes for a non-ActiveRecord model.
|
|
|
6
6
|
- Type casting and checking.
|
|
7
7
|
- Dirty tracking.
|
|
8
8
|
- List attribute names and values.
|
|
9
|
+
- Default values for attributes
|
|
9
10
|
- Handles integers, booleans, strings and times - a set of types that are very
|
|
10
11
|
easy to persist to and parse from JSON.
|
|
11
12
|
- Supports efficient serialization of attributes to JSON.
|
|
@@ -164,6 +165,31 @@ class User
|
|
|
164
165
|
events += new_event
|
|
165
166
|
end
|
|
166
167
|
end
|
|
168
|
+
|
|
169
|
+
# Supporting default attributes
|
|
170
|
+
|
|
171
|
+
class UserWithDefaults
|
|
172
|
+
extend ModelAttribute
|
|
173
|
+
|
|
174
|
+
attribute :name, :string, default: 'Charlie'
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
UserWithDefaults.attribute_defaults # => {:name=>"Charlie"}
|
|
178
|
+
|
|
179
|
+
user = UserWithDefaults.new
|
|
180
|
+
user.name # => "Charlie"
|
|
181
|
+
user.read_attribute(:name) # => "Charlie"
|
|
182
|
+
user.attributes # => {:name=>"Charlie"}
|
|
183
|
+
# attributes_for_json omits defaults to keep the JSON compact
|
|
184
|
+
user.attributes_for_json # => {}
|
|
185
|
+
# you can add them back in if you need them
|
|
186
|
+
user.attributes_for_json.merge(user.class.attribute_defaults) # => {:name=>"Charlie"}
|
|
187
|
+
# A default isn't a change
|
|
188
|
+
user.changes # => {}
|
|
189
|
+
user.changes_for_json # => {}
|
|
190
|
+
|
|
191
|
+
user.name = 'Bob'
|
|
192
|
+
user.attributes # => {:name=>"Bob"}
|
|
167
193
|
```
|
|
168
194
|
|
|
169
195
|
## Installation
|
data/Rakefile
CHANGED
data/lib/model_attribute.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "model_attribute/version"
|
|
2
|
-
require "model_attribute/
|
|
2
|
+
require "model_attribute/casts"
|
|
3
3
|
require "model_attribute/errors"
|
|
4
4
|
require "time"
|
|
5
5
|
|
|
@@ -8,17 +8,19 @@ module ModelAttribute
|
|
|
8
8
|
|
|
9
9
|
def self.extended(base)
|
|
10
10
|
base.send(:include, InstanceMethods)
|
|
11
|
-
base.instance_variable_set('@attribute_names',
|
|
12
|
-
base.instance_variable_set('@attribute_types',
|
|
11
|
+
base.instance_variable_set('@attribute_names', [])
|
|
12
|
+
base.instance_variable_set('@attribute_types', {})
|
|
13
|
+
base.instance_variable_set('@attribute_defaults', {})
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
def attribute(name, type)
|
|
16
|
+
def attribute(name, type, opts = {})
|
|
16
17
|
name = name.to_sym
|
|
17
18
|
type = type.to_sym
|
|
18
19
|
raise UnsupportedTypeError.new(type) unless SUPPORTED_TYPES.include?(type)
|
|
19
20
|
|
|
20
|
-
@attribute_names
|
|
21
|
-
@attribute_types[name]
|
|
21
|
+
@attribute_names << name
|
|
22
|
+
@attribute_types[name] = type
|
|
23
|
+
@attribute_defaults[name] = opts[:default] if opts.key?(:default)
|
|
22
24
|
|
|
23
25
|
self.class_eval(<<-CODE, __FILE__, __LINE__ + 1)
|
|
24
26
|
def #{name}=(value)
|
|
@@ -47,6 +49,10 @@ module ModelAttribute
|
|
|
47
49
|
@attribute_names
|
|
48
50
|
end
|
|
49
51
|
|
|
52
|
+
def attribute_defaults
|
|
53
|
+
@attribute_defaults
|
|
54
|
+
end
|
|
55
|
+
|
|
50
56
|
module InstanceMethods
|
|
51
57
|
def write_attribute(name, value, type = nil)
|
|
52
58
|
name = name.to_sym
|
|
@@ -56,7 +62,7 @@ module ModelAttribute
|
|
|
56
62
|
type ||= self.class.instance_variable_get('@attribute_types')[name]
|
|
57
63
|
raise InvalidAttributeNameError.new(name) unless type
|
|
58
64
|
|
|
59
|
-
value = cast(value, type)
|
|
65
|
+
value = Casts.cast(value, type)
|
|
60
66
|
return if value == read_attribute(name)
|
|
61
67
|
|
|
62
68
|
if changes.has_key? name
|
|
@@ -80,6 +86,8 @@ module ModelAttribute
|
|
|
80
86
|
instance_variable_get(ivar_name)
|
|
81
87
|
elsif !self.class.attributes.include?(name.to_sym)
|
|
82
88
|
raise InvalidAttributeNameError.new(name)
|
|
89
|
+
else
|
|
90
|
+
self.class.attribute_defaults[name.to_sym]
|
|
83
91
|
end
|
|
84
92
|
end
|
|
85
93
|
|
|
@@ -106,19 +114,19 @@ module ModelAttribute
|
|
|
106
114
|
alias_method :eql?, :==
|
|
107
115
|
|
|
108
116
|
def changes
|
|
109
|
-
@changes ||= {}
|
|
117
|
+
@changes ||= {}
|
|
110
118
|
end
|
|
111
119
|
|
|
112
120
|
# Attributes suitable for serializing to a JSON string.
|
|
113
121
|
#
|
|
114
122
|
# - Attribute keys are strings (for 'strict' JSON dumping).
|
|
115
|
-
# - Attributes with a nil value are omitted to speed serialization.
|
|
123
|
+
# - Attributes with a default or nil value are omitted to speed serialization.
|
|
116
124
|
# - :time attributes are serialized as an Integer giving the number of
|
|
117
125
|
# milliseconds since the epoch.
|
|
118
126
|
def attributes_for_json
|
|
119
127
|
self.class.attributes.each_with_object({}) do |name, attributes|
|
|
120
128
|
value = read_attribute(name)
|
|
121
|
-
|
|
129
|
+
if value != self.class.attribute_defaults[name.to_sym]
|
|
122
130
|
value = (value.to_f * 1000).to_i if value.is_a? Time
|
|
123
131
|
attributes[name.to_s] = value
|
|
124
132
|
end
|
|
@@ -151,52 +159,5 @@ module ModelAttribute
|
|
|
151
159
|
end.join(', ')
|
|
152
160
|
"#<#{self.class} #{attribute_string}>"
|
|
153
161
|
end
|
|
154
|
-
|
|
155
|
-
def cast(value, type)
|
|
156
|
-
return nil if value.nil?
|
|
157
|
-
|
|
158
|
-
case type
|
|
159
|
-
when :integer
|
|
160
|
-
int = Integer(value)
|
|
161
|
-
float = Float(value)
|
|
162
|
-
raise "Can't cast #{value.inspect} to an integer without loss of precision" unless int == float
|
|
163
|
-
int
|
|
164
|
-
when :boolean
|
|
165
|
-
if !!value == value
|
|
166
|
-
value
|
|
167
|
-
elsif value == 't'
|
|
168
|
-
true
|
|
169
|
-
elsif value == 'f'
|
|
170
|
-
false
|
|
171
|
-
else
|
|
172
|
-
raise "Can't cast #{value.inspect} to boolean"
|
|
173
|
-
end
|
|
174
|
-
when :time
|
|
175
|
-
case value
|
|
176
|
-
when Time
|
|
177
|
-
value
|
|
178
|
-
when Date, DateTime
|
|
179
|
-
value.to_time
|
|
180
|
-
when Integer
|
|
181
|
-
# Assume milliseconds since epoch.
|
|
182
|
-
Time.at(value / 1000.0)
|
|
183
|
-
when Numeric
|
|
184
|
-
# Numeric, but not an integer. Assume seconds since epoch.
|
|
185
|
-
Time.at(value)
|
|
186
|
-
else
|
|
187
|
-
Time.parse(value)
|
|
188
|
-
end
|
|
189
|
-
when :string
|
|
190
|
-
String(value)
|
|
191
|
-
when :json
|
|
192
|
-
if Json.valid?(value)
|
|
193
|
-
value
|
|
194
|
-
else
|
|
195
|
-
raise "JSON only supports nil, numeric, string, boolean and arrays and hashes of those."
|
|
196
|
-
end
|
|
197
|
-
else
|
|
198
|
-
raise UnsupportedTypeError.new(type)
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
162
|
end
|
|
202
163
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module ModelAttribute
|
|
2
|
+
module Casts
|
|
3
|
+
class << self
|
|
4
|
+
def cast(value, type)
|
|
5
|
+
return nil if value.nil?
|
|
6
|
+
|
|
7
|
+
case type
|
|
8
|
+
when :integer
|
|
9
|
+
int = Integer(value)
|
|
10
|
+
float = Float(value)
|
|
11
|
+
raise "Can't cast #{value.inspect} to an integer without loss of precision" unless int == float
|
|
12
|
+
int
|
|
13
|
+
when :boolean
|
|
14
|
+
if !!value == value
|
|
15
|
+
value
|
|
16
|
+
elsif value == 't'
|
|
17
|
+
true
|
|
18
|
+
elsif value == 'f'
|
|
19
|
+
false
|
|
20
|
+
else
|
|
21
|
+
raise "Can't cast #{value.inspect} to boolean"
|
|
22
|
+
end
|
|
23
|
+
when :time
|
|
24
|
+
case value
|
|
25
|
+
when Time
|
|
26
|
+
value
|
|
27
|
+
when Date, DateTime
|
|
28
|
+
value.to_time
|
|
29
|
+
when Integer
|
|
30
|
+
# Assume milliseconds since epoch.
|
|
31
|
+
Time.at(value / 1000.0)
|
|
32
|
+
when Numeric
|
|
33
|
+
# Numeric, but not an integer. Assume seconds since epoch.
|
|
34
|
+
Time.at(value)
|
|
35
|
+
else
|
|
36
|
+
Time.parse(value)
|
|
37
|
+
end
|
|
38
|
+
when :string
|
|
39
|
+
String(value)
|
|
40
|
+
when :json
|
|
41
|
+
if valid_json?(value)
|
|
42
|
+
value
|
|
43
|
+
else
|
|
44
|
+
raise "JSON only supports nil, numeric, string, boolean and arrays and hashes of those."
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
raise UnsupportedTypeError.new(type)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def valid_json?(value)
|
|
54
|
+
(value == nil ||
|
|
55
|
+
value == true ||
|
|
56
|
+
value == false ||
|
|
57
|
+
value.is_a?(Numeric) ||
|
|
58
|
+
value.is_a?(String) ||
|
|
59
|
+
(value.is_a?(Array) && valid_json_array?(value)) ||
|
|
60
|
+
(value.is_a?(Hash) && valid_json_hash?(value) ))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def valid_json_array?(array)
|
|
64
|
+
array.all? { |value| valid_json?(value) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def valid_json_hash?(hash)
|
|
68
|
+
hash.all? do |key, value|
|
|
69
|
+
key.is_a?(String) && valid_json?(value)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/model_attribute.gemspec
CHANGED
|
@@ -9,6 +9,10 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["David Waller"]
|
|
10
10
|
spec.email = ["dwaller@yammer-inc.com"]
|
|
11
11
|
spec.summary = %q{Attributes for non-ActiveRecord models}
|
|
12
|
+
spec.description = <<-EOF
|
|
13
|
+
Attributes for non-ActiveRecord models.
|
|
14
|
+
Smaller and simpler than Virtus, and adds dirty tracking.
|
|
15
|
+
EOF
|
|
12
16
|
spec.homepage = ""
|
|
13
17
|
spec.license = "MIT"
|
|
14
18
|
|
|
@@ -23,5 +27,4 @@ Gem::Specification.new do |spec|
|
|
|
23
27
|
spec.add_development_dependency "rspec-nc", "~> 0.2"
|
|
24
28
|
spec.add_development_dependency "guard", "~> 2.8"
|
|
25
29
|
spec.add_development_dependency "guard-rspec", "~> 4.3"
|
|
26
|
-
spec.add_development_dependency "pry-debugger"
|
|
27
30
|
end
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
class User
|
|
2
2
|
extend ModelAttribute
|
|
3
|
-
attribute :id,
|
|
4
|
-
attribute :paid,
|
|
5
|
-
attribute :name,
|
|
6
|
-
attribute :created_at,
|
|
7
|
-
attribute :profile,
|
|
3
|
+
attribute :id, :integer
|
|
4
|
+
attribute :paid, :boolean
|
|
5
|
+
attribute :name, :string
|
|
6
|
+
attribute :created_at, :time
|
|
7
|
+
attribute :profile, :json
|
|
8
|
+
attribute :reward_points, :integer, default: 0
|
|
8
9
|
|
|
9
10
|
def initialize(attributes = {})
|
|
10
11
|
set_attributes(attributes)
|
|
@@ -23,19 +24,29 @@ class UserWithoutId
|
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
RSpec.describe "a class using ModelAttribute" do
|
|
26
|
-
describe "
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
describe "class methods" do
|
|
28
|
+
describe ".attribute" do
|
|
29
|
+
context "passed an unrecognised type" do
|
|
30
|
+
it "raises an error" do
|
|
31
|
+
expect do
|
|
32
|
+
User.attribute :address, :custom_type
|
|
33
|
+
end.to raise_error(ModelAttribute::UnsupportedTypeError,
|
|
34
|
+
"Unsupported type :custom_type. " +
|
|
35
|
+
"Must be one of :integer, :boolean, :string, :time, :json.")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
29
38
|
end
|
|
30
|
-
end
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
describe ".attributes" do
|
|
41
|
+
it "returns an array of attribute names as symbols" do
|
|
42
|
+
expect(User.attributes).to eq([:id, :paid, :name, :created_at, :profile, :reward_points])
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe ".attribute_defaults" do
|
|
47
|
+
it "returns a hash of attributes that have non-nil defaults" do
|
|
48
|
+
expect(User.attribute_defaults).to eq({reward_points: 0})
|
|
49
|
+
end
|
|
39
50
|
end
|
|
40
51
|
end
|
|
41
52
|
|
|
@@ -295,6 +306,12 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
295
306
|
end
|
|
296
307
|
end
|
|
297
308
|
|
|
309
|
+
describe 'a defaulted attribute (reward_points)' do
|
|
310
|
+
it "returns the default when unset" do
|
|
311
|
+
expect(user.reward_points).to eq(0)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
298
315
|
describe "#write_attribute" do
|
|
299
316
|
it "does the same casting as using the writer method" do
|
|
300
317
|
user.write_attribute(:id, '3')
|
|
@@ -319,6 +336,12 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
319
336
|
expect(user.read_attribute(:id)).to be_nil
|
|
320
337
|
end
|
|
321
338
|
|
|
339
|
+
context "for an attribute with a default" do
|
|
340
|
+
it "returns the default if the attribute has not been set" do
|
|
341
|
+
expect(user.read_attribute(:reward_points)).to eq(0)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
322
345
|
it "raises an error if passed an invalid attribute name" do
|
|
323
346
|
expect do
|
|
324
347
|
user.read_attribute(:spelling_mistake)
|
|
@@ -330,7 +353,7 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
330
353
|
describe "#changes" do
|
|
331
354
|
let(:changes) { user.changes }
|
|
332
355
|
|
|
333
|
-
context "for a model instance created with no attributes" do
|
|
356
|
+
context "for a model instance created with no attributes except defaults" do
|
|
334
357
|
it "is empty" do
|
|
335
358
|
expect(changes).to be_empty
|
|
336
359
|
end
|
|
@@ -408,7 +431,7 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
408
431
|
end
|
|
409
432
|
end
|
|
410
433
|
|
|
411
|
-
describe "id_changed?" do
|
|
434
|
+
describe "#id_changed?" do
|
|
412
435
|
context "with no changes" do
|
|
413
436
|
it "returns false" do
|
|
414
437
|
expect(user.id_changed?).to eq(false)
|
|
@@ -470,8 +493,18 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
470
493
|
expect(user.attributes_for_json).to include("profile" => json)
|
|
471
494
|
end
|
|
472
495
|
|
|
473
|
-
it "omits attributes
|
|
474
|
-
expect(user.attributes_for_json).to_not include("name")
|
|
496
|
+
it "omits attributes still set to the default value" do
|
|
497
|
+
expect(user.attributes_for_json).to_not include("name", "reward_points")
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "includes an attribute changed from its default value" do
|
|
501
|
+
user.name = "Fred"
|
|
502
|
+
expect(user.attributes_for_json).to include("name" => "Fred")
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
it "includes an attribute changed from its default value to nil" do
|
|
506
|
+
user.reward_points = nil
|
|
507
|
+
expect(user.attributes_for_json).to include("reward_points" => nil)
|
|
475
508
|
end
|
|
476
509
|
end
|
|
477
510
|
|
|
@@ -531,12 +564,16 @@ RSpec.describe "a class using ModelAttribute" do
|
|
|
531
564
|
expect(user.inspect).to include('profile: {"interests"=>["coding", "social networks"], "rank"=>15}')
|
|
532
565
|
end
|
|
533
566
|
|
|
567
|
+
it "includes defaulted attributes" do
|
|
568
|
+
expect(user.inspect).to include('reward_points: 0')
|
|
569
|
+
end
|
|
570
|
+
|
|
534
571
|
it "includes the class name" do
|
|
535
572
|
expect(user.inspect).to include("User")
|
|
536
573
|
end
|
|
537
574
|
|
|
538
575
|
it "looks like '#<User id: 1, paid: true, name: ..., created_at: ...>'" do
|
|
539
|
-
expect(user.inspect).to eq("#<User id: 1, paid: true, name: \"Fred\", created_at: 2014-12-25 08:00:00 +0000, profile: {\"interests\"=>[\"coding\", \"social networks\"], \"rank\"=>15}>")
|
|
576
|
+
expect(user.inspect).to eq("#<User id: 1, paid: true, name: \"Fred\", created_at: 2014-12-25 08:00:00 +0000, profile: {\"interests\"=>[\"coding\", \"social networks\"], \"rank\"=>15}, reward_points: 0>")
|
|
540
577
|
end
|
|
541
578
|
end
|
|
542
579
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: model_attribute
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Waller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-04-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -94,21 +94,8 @@ dependencies:
|
|
|
94
94
|
- - ~>
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '4.3'
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - ! '>='
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '0'
|
|
104
|
-
type: :development
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - ! '>='
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '0'
|
|
111
|
-
description:
|
|
97
|
+
description: ! " Attributes for non-ActiveRecord models.\n Smaller and simpler
|
|
98
|
+
than Virtus, and adds dirty tracking.\n"
|
|
112
99
|
email:
|
|
113
100
|
- dwaller@yammer-inc.com
|
|
114
101
|
executables: []
|
|
@@ -117,6 +104,7 @@ extra_rdoc_files: []
|
|
|
117
104
|
files:
|
|
118
105
|
- .gitignore
|
|
119
106
|
- .rspec
|
|
107
|
+
- .travis.yml
|
|
120
108
|
- CHANGELOG.md
|
|
121
109
|
- Gemfile
|
|
122
110
|
- Guardfile
|
|
@@ -124,8 +112,8 @@ files:
|
|
|
124
112
|
- README.md
|
|
125
113
|
- Rakefile
|
|
126
114
|
- lib/model_attribute.rb
|
|
115
|
+
- lib/model_attribute/casts.rb
|
|
127
116
|
- lib/model_attribute/errors.rb
|
|
128
|
-
- lib/model_attribute/json.rb
|
|
129
117
|
- lib/model_attribute/version.rb
|
|
130
118
|
- model_attribute.gemspec
|
|
131
119
|
- performance_comparison.rb
|
data/lib/model_attribute/json.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module ModelAttribute
|
|
2
|
-
module Json
|
|
3
|
-
class << self
|
|
4
|
-
def valid?(value)
|
|
5
|
-
(value == nil ||
|
|
6
|
-
value == true ||
|
|
7
|
-
value == false ||
|
|
8
|
-
value.is_a?(Numeric) ||
|
|
9
|
-
value.is_a?(String) ||
|
|
10
|
-
(value.is_a?(Array) && valid_array?(value)) ||
|
|
11
|
-
(value.is_a?(Hash) && valid_hash?(value) ))
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def valid_array?(array)
|
|
17
|
-
array.all? { |value| valid?(value) }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def valid_hash?(hash)
|
|
21
|
-
hash.all? do |key, value|
|
|
22
|
-
key.is_a?(String) && valid?(value)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|