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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3a918d43aa402d0de13f3e8bcc28b1d4cbad074
4
- data.tar.gz: a706a4c34294af699a1efdbda86dd649ffd278f5
3
+ metadata.gz: c3da6f6da8006ae59da0d6b1266c2d2882042d15
4
+ data.tar.gz: 59054e7d56f394f0f81bad19f22fd1029efa7198
5
5
  SHA512:
6
- metadata.gz: 0187eb34dda842f89d9be39593e3168c1189ae7abbe61343b1ec5e80e14bebbfeaaebfd357f0c1c2257edd643534795f901f91104b2765f5ed614005ec0dd94f
7
- data.tar.gz: fab7de2ebac15f30943af023b644e93759131fc40e3a3a46523440e3da42980f88e55aaae551ee1aad1b00e64c705bd6d0e9931821f2b6a39340db62aa2abd1a
6
+ metadata.gz: b36b03a5ccd3f4e6700caa0b072a8ccf819d4d42c5d4076ef6641ef7a99a35ed335e24dc6a53e115f53abde94e872b1d569919e29d19cc2131ae9b20306ddb46
7
+ data.tar.gz: 9ff554ead5d5fe0eaed31d8841e5dbaccc0bdae59dc4afa2f9bcd9b9a25be1c146e7a0436bbc8a7829e96e1a1cd085bb019e7638cd9510f91d4a13b00f7f6b99
data/Gemfile CHANGED
@@ -20,4 +20,8 @@ end
20
20
 
21
21
  platforms :jruby do
22
22
  gem "activerecord-jdbcsqlite3-adapter"
23
+ end
24
+
25
+ group :development do
26
+ gem 'coveralls', require: false
23
27
  end
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Soulless
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/soulless.rb CHANGED
@@ -1,22 +1,11 @@
1
1
  require 'virtus'
2
2
  require 'securerandom'
3
- require 'active_support/core_ext/array/wrap'
4
- require 'active_support/core_ext/class/attribute'
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
@@ -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
@@ -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
@@ -1,5 +1,5 @@
1
- #require 'coveralls'
2
- #Coveralls.wear!
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
3
 
4
4
  require File.expand_path("../../spec/dummy/config/environment", __FILE__)
5
5
 
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.2.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-07 00:00:00.000000000 Z
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