soulless 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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