soulless 0.2.0 → 0.3.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 +4 -4
- data/Gemfile +4 -0
- data/README.md +28 -53
- data/lib/soulless/dirty.rb +48 -0
- data/lib/soulless/model.rb +3 -1
- data/lib/soulless/version.rb +1 -1
- data/lib/soulless.rb +5 -15
- data/spec/dirty_spec.rb +56 -0
- data/spec/soulless_spec.rb +5 -0
- data/spec/spec_helper.rb +2 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3da6f6da8006ae59da0d6b1266c2d2882042d15
|
4
|
+
data.tar.gz: 59054e7d56f394f0f81bad19f22fd1029efa7198
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b36b03a5ccd3f4e6700caa0b072a8ccf819d4d42c5d4076ef6641ef7a99a35ed335e24dc6a53e115f53abde94e872b1d569919e29d19cc2131ae9b20306ddb46
|
7
|
+
data.tar.gz: 9ff554ead5d5fe0eaed31d8841e5dbaccc0bdae59dc4afa2f9bcd9b9a25be1c146e7a0436bbc8a7829e96e1a1cd085bb019e7638cd9510f91d4a13b00f7f6b99
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -46,59 +46,6 @@ class UserSignupForm
|
|
46
46
|
end
|
47
47
|
```
|
48
48
|
|
49
|
-
### Default Values
|
50
|
-
|
51
|
-
When defining attributes it's possible to specify default values.
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
class UserSignupForm
|
55
|
-
|
56
|
-
...
|
57
|
-
|
58
|
-
attribute :name, String, default: 'Anthony'
|
59
|
-
|
60
|
-
...
|
61
|
-
end
|
62
|
-
```
|
63
|
-
|
64
|
-
### Embedded Values
|
65
|
-
|
66
|
-
It's possible to use other Soulless objects as attribute types.
|
67
|
-
|
68
|
-
```ruby
|
69
|
-
class User
|
70
|
-
include Soulless.model
|
71
|
-
|
72
|
-
attribute :name, String
|
73
|
-
attribute :email, String
|
74
|
-
attribute :password, String
|
75
|
-
end
|
76
|
-
|
77
|
-
class UserSignupForm
|
78
|
-
include Soulless.model
|
79
|
-
|
80
|
-
attribute :user, User
|
81
|
-
end
|
82
|
-
```
|
83
|
-
|
84
|
-
### Collection Coercions
|
85
|
-
|
86
|
-
Define collections with specific types.
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
class PhoneNumber
|
90
|
-
include Soulless.model
|
91
|
-
|
92
|
-
attribute :number, String
|
93
|
-
end
|
94
|
-
|
95
|
-
class Person
|
96
|
-
include Soulless.model
|
97
|
-
|
98
|
-
attribute :phone_numbers, Array[PhoneNumber]
|
99
|
-
end
|
100
|
-
```
|
101
|
-
|
102
49
|
### Processing an Object
|
103
50
|
|
104
51
|
Soulless let's _you_ define what happens when your object is ready to be processed.
|
@@ -260,6 +207,34 @@ person.errors[:spouse] # => ["is invalid"]
|
|
260
207
|
person.spouse.errors[:name] # => ["can't be blank"]
|
261
208
|
```
|
262
209
|
|
210
|
+
### Dirty Attributes
|
211
|
+
|
212
|
+
Dirty attribute allow you to track changes to a Soulless object before it's saved.
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
person = Person.name(name: "Anthony", spouse: { name: "Mary Jane Watson" })
|
216
|
+
person.name = 'Peter Parker'
|
217
|
+
person.changed? # => true
|
218
|
+
person.changed # => ["name"]
|
219
|
+
person.changes # => { name: ["Anthony", "Peter Parker"] }
|
220
|
+
person.name_changed? # => true
|
221
|
+
person.name_was # => "Anthony"
|
222
|
+
person.name_change # => ["Anthony", "Peter Parker"]
|
223
|
+
```
|
224
|
+
|
225
|
+
Works on ```has_one``` and ```has_many``` too.
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
person.spouse.name = 'Gwen Stacy'
|
229
|
+
person.spouse.changed? # => true
|
230
|
+
person.spouse.changed # => ["name"]
|
231
|
+
person.spouse.changes # => { name: ["Mary Jane Watson", "Gwen Stacy"] }
|
232
|
+
person.spouse.name_changed? # => true
|
233
|
+
person.spouse.name_was # => "Mary Jane Watson"
|
234
|
+
person.spouse.name_change # => ["Mary Jane Watson", "Gwen Stacy"]
|
235
|
+
person.changed? # => false
|
236
|
+
```
|
237
|
+
|
263
238
|
### I18n
|
264
239
|
|
265
240
|
Define locales similar to how you would define them in Rails.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Soulless
|
2
|
+
module Dirty
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
def initialize(params = {})
|
6
|
+
super
|
7
|
+
init_dirty(attribute_set.map { |a| a.name })
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def init_dirty(attributes)
|
12
|
+
define_dirty_attributes(attributes)
|
13
|
+
define_dirty_methods(attributes)
|
14
|
+
@changed_attributes = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def changes_applied
|
18
|
+
@previously_changed = changed
|
19
|
+
@changed_attributes = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_dirty_attributes(attributes)
|
23
|
+
self.class.define_attribute_methods(attributes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def define_dirty_methods(attributes)
|
27
|
+
attributes.each do |attribute|
|
28
|
+
define_dirty_reader(attribute)
|
29
|
+
define_dirty_writer(attribute)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_dirty_reader(name)
|
34
|
+
self.class.send(:define_method, "#{name}".to_sym) do
|
35
|
+
instance_variable_get("@#{name}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_dirty_writer(name)
|
40
|
+
self.class.send(:define_method, "#{name}=".to_sym) do |value|
|
41
|
+
send("#{name}_will_change!") unless instance_variable_get("@#{name}") == value
|
42
|
+
super(value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/soulless/model.rb
CHANGED
@@ -4,8 +4,9 @@ module Soulless
|
|
4
4
|
base.class_eval do
|
5
5
|
extend ActiveModel::Naming
|
6
6
|
extend ActiveModel::Translation
|
7
|
-
include ActiveModel::Validations
|
8
7
|
include ActiveModel::Conversion
|
8
|
+
include ActiveModel::Dirty
|
9
|
+
include ActiveModel::Validations
|
9
10
|
|
10
11
|
class << self
|
11
12
|
def i18n_scope
|
@@ -20,6 +21,7 @@ module Soulless
|
|
20
21
|
def save
|
21
22
|
if valid?
|
22
23
|
persist!
|
24
|
+
changes_applied
|
23
25
|
true
|
24
26
|
else
|
25
27
|
false
|
data/lib/soulless/version.rb
CHANGED
data/lib/soulless.rb
CHANGED
@@ -1,22 +1,11 @@
|
|
1
1
|
require 'virtus'
|
2
2
|
require 'securerandom'
|
3
|
-
require 'active_support
|
4
|
-
require '
|
5
|
-
require 'active_support/core_ext/module/delegation'
|
6
|
-
require 'active_support/callbacks'
|
7
|
-
require 'active_support/concern'
|
8
|
-
require 'active_support/inflector'
|
9
|
-
require 'active_model/naming'
|
10
|
-
require 'active_model/translation'
|
11
|
-
require 'active_model/callbacks'
|
12
|
-
require 'active_model/validator'
|
13
|
-
require 'active_model/errors'
|
14
|
-
require 'active_model/validations'
|
15
|
-
require 'active_model/conversion'
|
16
|
-
require 'active_model/version'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_model'
|
17
5
|
|
18
|
-
require 'soulless/model'
|
19
6
|
require 'soulless/associations'
|
7
|
+
require 'soulless/dirty'
|
8
|
+
require 'soulless/model'
|
20
9
|
require 'soulless/validations'
|
21
10
|
require 'soulless/version'
|
22
11
|
|
@@ -30,6 +19,7 @@ module Soulless
|
|
30
19
|
object.send(:include, Model)
|
31
20
|
object.send(:include, Associations)
|
32
21
|
object.send(:include, Validations)
|
22
|
+
object.send(:include, Dirty)
|
33
23
|
end
|
34
24
|
mod
|
35
25
|
end
|
data/spec/dirty_spec.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Soulless::Dirty do
|
4
|
+
before(:each) do
|
5
|
+
@dummy_class = DummyClass.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should support dirty attributes' do
|
9
|
+
defined?(:changed?).should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should record attribute changes' do
|
13
|
+
@dummy_class.name_changed?.should be_false
|
14
|
+
@dummy_class.name = 'Yaw'
|
15
|
+
@dummy_class.name_changed?.should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should correctly record changes to objects with initialized values' do
|
19
|
+
@dummy_class = DummyClass.new(name: 'Biff')
|
20
|
+
@dummy_class.name_changed?.should be_false
|
21
|
+
@dummy_class.name = 'Anthony'
|
22
|
+
@dummy_class.name_changed?.should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should record changes in a has_one association' do
|
26
|
+
@dummy_association = DummyAssociation.new(spouse: { name: 'Megan' })
|
27
|
+
@dummy_association.spouse.name_changed?.should be_false
|
28
|
+
@dummy_association.spouse.name = 'Megan Jr'
|
29
|
+
@dummy_association.spouse.name_changed?.should be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should record changes in a has_many association' do
|
33
|
+
@dummy_association = DummyAssociation.new(friends: [{ name: 'Yaw' }])
|
34
|
+
@dummy_association.friends[0].name_changed?.should be_false
|
35
|
+
@dummy_association.friends[0].name = 'Biff'
|
36
|
+
@dummy_association.friends[0].name_changed?.should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should reset its dirty state when saved' do
|
40
|
+
@dummy_class.name = 'Biff'
|
41
|
+
@dummy_class.save
|
42
|
+
@dummy_class.changed?.should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should not reset its dirty state if validations fail' do
|
46
|
+
@dummy_class.name = nil
|
47
|
+
@dummy_class.save
|
48
|
+
@dummy_class.changed?.should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should record changed made before #save was called in previous_changes' do
|
52
|
+
@dummy_class.name = 'Biff'
|
53
|
+
@dummy_class.save
|
54
|
+
@dummy_class.previous_changes.should_not be_empty
|
55
|
+
end
|
56
|
+
end
|
data/spec/soulless_spec.rb
CHANGED
@@ -16,6 +16,11 @@ describe Soulless do
|
|
16
16
|
@dummy_class.saved.should be_true
|
17
17
|
end
|
18
18
|
|
19
|
+
it 'should call #persist! when #update_attributes is called' do
|
20
|
+
@dummy_class.update_attributes(name: 'Biff')
|
21
|
+
@dummy_class.saved.should be_true
|
22
|
+
end
|
23
|
+
|
19
24
|
it 'should not call #persist! if attributes are invalid' do
|
20
25
|
@dummy_class.name = nil
|
21
26
|
@dummy_class.save.should be_false
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soulless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- Rakefile
|
124
124
|
- lib/soulless.rb
|
125
125
|
- lib/soulless/associations.rb
|
126
|
+
- lib/soulless/dirty.rb
|
126
127
|
- lib/soulless/locale/en.yml
|
127
128
|
- lib/soulless/model.rb
|
128
129
|
- lib/soulless/validations.rb
|
@@ -132,6 +133,7 @@ files:
|
|
132
133
|
- soulless.gemspec
|
133
134
|
- spec/associated_validator_spec.rb
|
134
135
|
- spec/associations_spec.rb
|
136
|
+
- spec/dirty_spec.rb
|
135
137
|
- spec/dummy/.gitignore
|
136
138
|
- spec/dummy/README.rdoc
|
137
139
|
- spec/dummy/Rakefile
|
@@ -214,6 +216,7 @@ summary: Create Rails style models without the database.
|
|
214
216
|
test_files:
|
215
217
|
- spec/associated_validator_spec.rb
|
216
218
|
- spec/associations_spec.rb
|
219
|
+
- spec/dirty_spec.rb
|
217
220
|
- spec/dummy/.gitignore
|
218
221
|
- spec/dummy/README.rdoc
|
219
222
|
- spec/dummy/Rakefile
|