soulless 0.6.0 → 1.0.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -18
  3. data/.rspec +1 -1
  4. data/.travis.yml +7 -12
  5. data/CODE_OF_CONDUCT.md +49 -0
  6. data/Gemfile +17 -13
  7. data/LICENSE.txt +17 -18
  8. data/README.md +8 -181
  9. data/Rakefile +4 -8
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/docker-compose.yml +11 -0
  13. data/lib/soulless/attributes.rb +33 -0
  14. data/lib/soulless/callbacks.rb +13 -0
  15. data/lib/soulless/dirty.rb +10 -8
  16. data/lib/soulless/inheritance.rb +120 -124
  17. data/lib/soulless/model.rb +24 -63
  18. data/lib/soulless/validations/uniqueness_validator.rb +7 -8
  19. data/lib/soulless/validations.rb +1 -2
  20. data/lib/soulless/version.rb +1 -1
  21. data/lib/soulless.rb +5 -23
  22. data/soulless.gemspec +12 -13
  23. metadata +30 -173
  24. data/lib/soulless/accessors.rb +0 -51
  25. data/lib/soulless/associations.rb +0 -35
  26. data/lib/soulless/locale/en.yml +0 -30
  27. data/lib/soulless/railtie.rb +0 -7
  28. data/lib/soulless/validations/associated_validator.rb +0 -17
  29. data/spec/associated_validator_spec.rb +0 -31
  30. data/spec/associations_spec.rb +0 -65
  31. data/spec/dirty_spec.rb +0 -54
  32. data/spec/dummy/.gitignore +0 -17
  33. data/spec/dummy/README.rdoc +0 -28
  34. data/spec/dummy/Rakefile +0 -6
  35. data/spec/dummy/app/assets/images/.keep +0 -0
  36. data/spec/dummy/app/assets/javascripts/application.js +0 -16
  37. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  38. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  39. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  40. data/spec/dummy/app/forms/dummy_form.rb +0 -7
  41. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  42. data/spec/dummy/app/mailers/.keep +0 -0
  43. data/spec/dummy/app/models/.keep +0 -0
  44. data/spec/dummy/app/models/concerns/.keep +0 -0
  45. data/spec/dummy/app/models/dummy_model.rb +0 -6
  46. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  47. data/spec/dummy/bin/bundle +0 -3
  48. data/spec/dummy/bin/rails +0 -4
  49. data/spec/dummy/bin/rake +0 -4
  50. data/spec/dummy/config/application.rb +0 -28
  51. data/spec/dummy/config/boot.rb +0 -6
  52. data/spec/dummy/config/database.yml +0 -25
  53. data/spec/dummy/config/environment.rb +0 -5
  54. data/spec/dummy/config/environments/development.rb +0 -29
  55. data/spec/dummy/config/environments/production.rb +0 -80
  56. data/spec/dummy/config/environments/test.rb +0 -36
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  58. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  59. data/spec/dummy/config/initializers/inflections.rb +0 -16
  60. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  61. data/spec/dummy/config/initializers/secret_token.rb +0 -12
  62. data/spec/dummy/config/initializers/session_store.rb +0 -3
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  64. data/spec/dummy/config/locales/en.yml +0 -23
  65. data/spec/dummy/config/routes.rb +0 -56
  66. data/spec/dummy/config.ru +0 -4
  67. data/spec/dummy/db/migrate/20131106221200_create_dummy_models.rb +0 -11
  68. data/spec/dummy/db/schema.rb +0 -24
  69. data/spec/dummy/db/seeds.rb +0 -7
  70. data/spec/dummy/db/test.sqlite3 +0 -0
  71. data/spec/dummy/lib/assets/.keep +0 -0
  72. data/spec/dummy/lib/tasks/.keep +0 -0
  73. data/spec/dummy/log/.keep +0 -0
  74. data/spec/dummy/public/404.html +0 -58
  75. data/spec/dummy/public/422.html +0 -58
  76. data/spec/dummy/public/500.html +0 -57
  77. data/spec/dummy/public/favicon.ico +0 -0
  78. data/spec/dummy/public/robots.txt +0 -5
  79. data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
  80. data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
  81. data/spec/inheritance_spec.rb +0 -51
  82. data/spec/soulless_spec.rb +0 -61
  83. data/spec/spec_helper.rb +0 -38
  84. data/spec/support/dummy_association.rb +0 -30
  85. data/spec/support/dummy_class.rb +0 -20
  86. data/spec/support/dummy_model_inheritance.rb +0 -10
  87. data/spec/support/dummy_soulless_inheritance.rb +0 -10
  88. data/spec/support/en.yml +0 -8
  89. data/spec/uniqueness_validator_spec.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46d038cfbf26cbc9feeae03cbd119375fdf31454
4
- data.tar.gz: 983e7052834515c4f6b11365e1009526bd1ad60d
3
+ metadata.gz: afcfdbb737a946c2f08e73de14f36121acf79300
4
+ data.tar.gz: 32c52dad7be7cd46dc5bc63176e24131b06f1909
5
5
  SHA512:
6
- metadata.gz: 1990e836f0368dbd64ce0ad0d725c3595ecd7d154e76543bba3a2f463e1165880fb9631a85dace9e6a4ff7d0447e1b4906156b24dae515c41f34dbe8909320bd
7
- data.tar.gz: cbf63551bd3c48a725f7fd788acc2cff6efac2f64d6024d74a905002d87344363d6452609935a56035e17ce1804cb3e84fa9cd806e7ae99ee16fc4246977bce2
6
+ metadata.gz: 711338a9d4b320d44cf6aff3f5bc340da6b520b31dafd049c1c7749d76df2053b543fd334e1ec95a964fa9e81460e5c41e1397a2a1286916ce3613b68c2bc5c3
7
+ data.tar.gz: 82d067106ed7b91d224ee12e0b89ddbd4b24fc020938e55e2bfd0c2c129089590cbe37d4c21bf8cc320105a4fcb42f5266f7057f4131789981990a079cb8dd90
data/.gitignore CHANGED
@@ -1,20 +1,14 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .ruby*
18
11
  .rbenv*
19
12
  .rvmrc
20
- .DS_Store
13
+ .DS_Store
14
+ *.sqlite3
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
+ --format documentation
1
2
  --color
2
- --require spec_helper
data/.travis.yml CHANGED
@@ -1,21 +1,16 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.0
3
+ - 2.2.2
4
+ - 2.3.0
6
5
  - ruby-head
7
- - jruby-19mode
8
6
  - jruby-head
9
- - rbx-2
10
7
  env:
11
- - "RAILS_VERSION=3.2.0"
12
- - "RAILS_VERSION=4.0.0"
13
- - "RAILS_VERSION=master"
14
- script:
15
- - cd spec/dummy; bundle exec rake db:migrate
16
- - cd ../../; bundle exec rake spec
8
+ - "ACTIVE_RECORD_VERSION=4.2.0"
9
+ - "ACTIVE_RECORD_VERSION=~5.0.0"
10
+ - "ACTIVE_RECORD_VERSION=master"
17
11
  matrix:
18
12
  allow_failures:
19
- - env: "RAILS_VERSION=master"
13
+ - env: "ACTIVE_RECORD_VERSION=master"
20
14
  - rvm: ruby-head
21
15
  - rvm: jruby-head
16
+ sudo: false
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at TODO: Write your email address. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile CHANGED
@@ -1,27 +1,31 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in ar_book_finder.gemspec
3
+ # Specify your gem's dependencies in soulless.gemspec
4
4
  gemspec
5
5
 
6
- rails_version = case ENV['RAILS_VERSION'] || 'default'
6
+ active_record_version = case ENV['ACTIVE_RECORD_VERSION'] || 'default'
7
+
7
8
  when 'master'
8
9
  { git: 'https://github.com/rails/rails.git' }
9
10
  when 'default'
10
- '~> 4.0'
11
+ '~> 4.2'
11
12
  else
12
- "~> #{ENV['RAILS_VERSION']}"
13
- end
14
-
15
- gem 'rails', rails_version
16
-
17
- platforms :ruby do
18
- gem 'sqlite3'
13
+ "~> #{ENV['ACTIVE_RECORD_VERSION']}"
19
14
  end
20
15
 
21
- platforms :jruby do
22
- gem "activerecord-jdbcsqlite3-adapter"
16
+ group :test do
17
+ gem 'coveralls', require: false
18
+ gem 'simplecov', require: false
23
19
  end
24
20
 
25
21
  group :development do
26
- gem 'coveralls', require: false
22
+ gem 'activerecord', '>= 4.2.0', '< 5.1'
23
+
24
+ platforms :ruby do
25
+ gem 'sqlite3'
26
+ end
27
+
28
+ platforms :jruby do
29
+ gem "activerecord-jdbcsqlite3-adapter"
30
+ end
27
31
  end
data/LICENSE.txt CHANGED
@@ -1,22 +1,21 @@
1
- Copyright (c) 2013 Anthony Smith
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2016 TODO: Write your name
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -21,12 +21,10 @@ Or install it yourself as:
21
21
 
22
22
  ## Usage
23
23
 
24
- Just define a plain-old-ruby-object, include Soulless and get crackin'!
24
+ Just define a plain-old-ruby-object, inherit from `Soulless::Model` and get crackin'!
25
25
 
26
26
  ```ruby
27
- class UserSignupForm
28
- include Soulless.model
29
-
27
+ class UserSignupForm < Soulless::Model
30
28
  attribute :name, String
31
29
  attribute :email, String
32
30
  attribute :password, String
@@ -38,40 +36,6 @@ class UserSignupForm
38
36
 
39
37
  validates :password, presence: true,
40
38
  lenght: { is_at_least: 8 }
41
-
42
- private
43
- def persist!
44
- # Define what to do when this form is ready to be saved.
45
- end
46
- end
47
- ```
48
-
49
- ### Processing an Object
50
-
51
- Soulless let's _you_ define what happens when your object is ready to be processed.
52
-
53
- ```ruby
54
- class UserSignupForm
55
-
56
- ...
57
-
58
- private
59
- def persist!
60
- user = User.create!(name: name, email: email, password: password)
61
- UserMailer.send_activation_code(user).deliver
62
- user.charge_card!
63
- end
64
- end
65
- ```
66
-
67
- Process your Soulless object by calling ```save```. Just like a Rails model!
68
-
69
- ```ruby
70
- form = UserSignupForm.new(name: name, email: email, password: passord)
71
- if form.save
72
- # Called persist! and all is good!
73
- else
74
- # Looks like a validation failed. Try again.
75
39
  end
76
40
  ```
77
41
 
@@ -133,106 +97,13 @@ Just let the validator know what ActiveRecord model to use when performing the v
133
97
 
134
98
  If your Soulless object attribute doesn't match up to the ActiveRecord model attribute just map it using the ```attribute``` option.
135
99
 
136
- ### ```has_one``` and ```has_many``` Associations
137
-
138
- When you need associations use ```has_one``` and ```has_many```. Look familiar?
139
-
140
- ```ruby
141
- class Person
142
- include Soulless.model
143
-
144
- attribute :name, String
145
-
146
- validates :name, presence: true
147
-
148
- has_one :spouse do
149
- attribute :name, String
150
- end
151
-
152
- has_many :friends do
153
- attribute :name, String
154
- end
155
- end
156
- ```
157
-
158
- You can set ```has_one``` and ```has_many``` attributes by setting their values hashes and hash arrays.
159
-
160
- ```ruby
161
- person = Person.new(name: 'Anthony')
162
- person.spouse = { name: 'Megan' }
163
- person.friends = [{ name: 'Yaw' }, { name: 'Biff' }]
164
- ```
165
-
166
- It's also possible for an association to inherit from a parent class and then extend functionality.
167
-
168
- ```ruby
169
- class Person
170
- include Soulless.model
171
-
172
- attribute :name, String
173
-
174
- validates :name, presence: true
175
-
176
- has_one :spouse, Person do # inherits 'name' and validation from Person
177
- attribute :anniversary, DateTime
178
-
179
- validates :anniversary, presence: true
180
- end
181
-
182
- has_many :friends, Person # just inherit from Person, don't extend
183
- end
184
- ```
185
-
186
- Your association has access to it's ```parent``` object as well.
187
-
188
- ```ruby
189
- class Person
190
- include Soulless.model
191
-
192
- attribute :name, String
193
-
194
- validates :name, presence: true
195
-
196
- has_one :children do
197
- attribute :name, String, default: lambda { "#{parent.name} Jr." }
198
- end
199
- end
200
- ```
201
-
202
- When you need to make sure an association is valid before processing the object use ```validates_associated```.
203
-
204
- ```ruby
205
- class Person
206
-
207
- ...
208
-
209
- has_one :spouse do
210
- attribute :name, String
211
-
212
- validates :name, presence: true
213
- end
214
-
215
- validates_associated :spouse
216
-
217
- ...
218
-
219
- end
220
-
221
- person = Person.new(name: 'Anthony')
222
- person.spouse = { name: nil }
223
- person.valid? # => false
224
- person.errors[:spouse] # => ["is invalid"]
225
- person.spouse.errors[:name] # => ["can't be blank"]
226
- ```
227
-
228
100
  ### Callbacks
229
101
 
230
- Soulless supports the validation and save callbacks. You can use these callbacks
231
- as you would on a Rails model.
102
+ Soulless supports the validation callback. You can use this callback as you
103
+ would on a Rails model.
232
104
 
233
105
  ```ruby
234
- class Person
235
- include Soulless.model
106
+ class Person < Soulless::Model
236
107
 
237
108
  attribute :name, String
238
109
 
@@ -240,27 +111,15 @@ class Person
240
111
 
241
112
  before_validation :change_name_to_bart_simpson
242
113
 
243
- before_save :change_name_to_mickey_mouse
244
-
245
- has_one :children do
246
- attribute :name, String, default: lambda { "#{parent.name} Jr." }
247
- end
248
-
249
114
  private
250
115
  def change_name_to_bart_simpson
251
116
  self.name = 'Bart Simpson'
252
117
  end
253
-
254
- def change_name_to_mickey_mouse
255
- self.name = 'Mickey Mouse'
256
- end
257
118
  end
258
119
 
259
120
  person = Person.new(name: 'Anthony')
260
121
  person.valid?
261
122
  person.name # => "Bart Simpson"
262
- person.save
263
- person.name # => "Mickey Mouse"
264
123
  ```
265
124
 
266
125
  ### Dirty Attributes
@@ -278,19 +137,6 @@ person.name_was # => "Anthony"
278
137
  person.name_change # => ["Anthony", "Peter Parker"]
279
138
  ```
280
139
 
281
- Works on ```has_one``` and ```has_many``` too.
282
-
283
- ```ruby
284
- person.spouse.name = 'Gwen Stacy'
285
- person.spouse.changed? # => true
286
- person.spouse.changed # => ["name"]
287
- person.spouse.changes # => { name: ["Mary Jane Watson", "Gwen Stacy"] }
288
- person.spouse.name_changed? # => true
289
- person.spouse.name_was # => "Mary Jane Watson"
290
- person.spouse.name_change # => ["Mary Jane Watson", "Gwen Stacy"]
291
- person.changed? # => false
292
- ```
293
-
294
140
  ### Inheritance
295
141
 
296
142
  One of the biggest pitfalls of the form object pattern is duplication of code. It's not uncommon for a form object to define attributes and validations that are identical to the model it represets.
@@ -307,9 +153,7 @@ end
307
153
  ```
308
154
 
309
155
  ```ruby
310
- class UserSignupForm
311
- include Soulless.model
312
-
156
+ class UserSignupForm < Soulless::Model
313
157
  inherit_from(User)
314
158
  end
315
159
  ```
@@ -330,9 +174,7 @@ The ```#inherit_from(klass, options = {})``` method also allows you to provide o
330
174
  If you don't want to inherit the ```email``` attribute define it using the ```exclude``` option.
331
175
 
332
176
  ```ruby
333
- class UserSignupForm
334
- include Soulless.model
335
-
177
+ class UserSignupForm < Soulless::Model
336
178
  inherit_from(User, exclude: :email)
337
179
  end
338
180
 
@@ -345,9 +187,7 @@ form.errors.messages # => { name: ["can't be blank"] }
345
187
  You can also flip it around if you only want the ```name``` attribute by using the ```only``` option.
346
188
 
347
189
  ```ruby
348
- class UserSignupForm
349
- include Soulless.model
350
-
190
+ class UserSignupForm < Soulless::Model
351
191
  inherit_from(User, only: :name)
352
192
  end
353
193
 
@@ -387,19 +227,6 @@ en:
387
227
  blank: "there's nothing here"
388
228
  ```
389
229
 
390
- For attributes defined as ```has_one``` and ```has_many``` associations use the enclosing class as the locale key's namespace.
391
-
392
- ```yaml
393
- en:
394
- soulless:
395
- errors:
396
- models:
397
- person/spouse:
398
- attributes:
399
- name:
400
- blank: "there's nothing here"
401
- ```
402
-
403
230
  ## Contributing
404
231
 
405
232
  1. Fork it
data/Rakefile CHANGED
@@ -1,10 +1,6 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
2
3
 
3
- require 'rspec/core'
4
- require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- RSpec::Core::RakeTask.new(:spec) do |spec|
7
- spec.pattern = FileList['spec/**/*_spec.rb']
8
- end
9
-
10
- task default: :spec
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "soulless"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ version: '2'
2
+ services:
3
+ lib:
4
+ image: sticksnleaves/ruby-project:2.3
5
+ command: rspec
6
+ volumes:
7
+ - .:/usr/src/app
8
+ - lib.volume:/usr/local/bundle
9
+ volumes:
10
+ lib.volume:
11
+ driver: local
@@ -0,0 +1,33 @@
1
+ module Soulless
2
+ module Attributes
3
+ module ClassMethods
4
+ def attribute(name, type = nil, options = {})
5
+ super(name, type, options) if super
6
+
7
+ define_attribute_methods(name)
8
+
9
+ define_reader(name)
10
+ define_writer(name)
11
+ end
12
+
13
+ def define_reader(attribute)
14
+ define_method(attribute.to_sym) do
15
+ attribute_set[attribute.to_sym].get(self)
16
+ end
17
+ end
18
+
19
+ def define_writer(attribute)
20
+ define_method("#{attribute}=".to_sym) do |value|
21
+ send("#{attribute}_will_change!") unless value == attribute_set[attribute.to_sym].get(self)
22
+ super(value)
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.prepended(base)
28
+ class << base
29
+ prepend ClassMethods
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Soulless
2
+ module Callbacks
3
+ def self.prepended(base)
4
+ base.define_model_callbacks :validation
5
+ end
6
+
7
+ def valid?(context = nil)
8
+ run_callbacks :validation do
9
+ super(context)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,13 +1,15 @@
1
1
  module Soulless
2
2
  module Dirty
3
- private
4
- def init_dirty
5
- @changed_attributes = {}
3
+ def apply_changes
4
+ changes_applied
6
5
  end
7
-
8
- def changes_applied
9
- @previously_changed = changed
10
- @changed_attributes = {}
6
+
7
+ def reload_changes!
8
+ clear_changes_information
9
+ end
10
+
11
+ def rollback_changes!(attributes = changed)
12
+ restore_attributes(attributes)
11
13
  end
12
14
  end
13
- end
15
+ end