active_record-acts_as 1.0.7 → 1.0.8

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: 7387f8a9b958e1010c9c86367631e5be078d6329
4
- data.tar.gz: 31705e7f709ae00673bc2cf9bddcf72cc7a2eda9
3
+ metadata.gz: b9ec0528a63347a0575f88a79865139353ed16b2
4
+ data.tar.gz: 03ff53a5a895ef19f2d740e85327f93afa76dafc
5
5
  SHA512:
6
- metadata.gz: 507a0fd8e3609ceb749a1f8a3ee9ae051de0094fb769778a661ff91f0ed9bf0bb4f8001267c68db76f70f02f64f0c088d48533c599f40d76b12eacf1e8932b04
7
- data.tar.gz: aebd0d7c848b0f53639491582c3d29187ed0d152324d861ebfbbb0441f792c83a61f95bb8d0d8ccce6993be6f899203dc0d1c790ac523c09d16d3f55179a4e85
6
+ metadata.gz: d4a00877c147b27f50ecc2abaf15abe4578e2ee5cdf45b2c6c3b9acbae4e2bc3f78700bbb0da94e07ed36d685a707bd71033759e88a07b5added7b22c89d01bb
7
+ data.tar.gz: cfd9cd5ba545e01f676f418c09b5cb161d83428c44869e8dd95f28f014c71474a93a469004dffb987c9460093603ff2a2673e90df9604aaaa61c6541c83b14a7
data/.travis.yml CHANGED
@@ -1,5 +1,8 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  rvm:
3
- - 2.1.1
4
+ - 2.3.0
5
+ - 2.2.3
6
+ - 2.1.7
4
7
  - 2.0.0
5
8
  - 1.9.3
data/README.md CHANGED
@@ -86,8 +86,13 @@ change_table :products do |t|
86
86
  end
87
87
  ```
88
88
 
89
- Now `Pen` and `Book` *acts as* `Product`, i.e. they inherit `Product`s *attributes*,
90
- *methods* and *validations*. Now you can do things like these:
89
+ **Make sure** that column names do not match on parent and subclass tables,
90
+ that will make SQL statements ambiguous and invalid!
91
+ Specially **DO NOT** use timestamps on subclasses, if you need them define them
92
+ on parent table and they will be touched after submodel updates.
93
+
94
+ Now `Pen` and `Book` **acts as** `Product`, i.e. they inherit `Product`s **attributes**,
95
+ **methods** and **validations**. Now you can do things like these:
91
96
 
92
97
  ```Ruby
93
98
  Pen.create name: 'Penie!', price: 0.8, color: 'red'
@@ -171,6 +176,28 @@ Replace `acts_as_superclass` in models with `actable` and if you where using
171
176
  `:as_relation_superclass` option on `create_table` remove it and use `t.actable` on column definitions.
172
177
 
173
178
 
179
+ ## RSpec custom matchers
180
+
181
+ To use this library custom RSpec matchers, you must require the `rspec/acts_as_matchers` file.
182
+
183
+ Examples:
184
+
185
+ ```Ruby
186
+ require "active_record/acts_as/matchers"
187
+
188
+ RSpec.describe "Pen acts like a Product" do
189
+ it { is_expected.to act_as(:product) }
190
+ it { is_expected.to act_as(Product) }
191
+
192
+ it { expect(Person).to act_as(:product) }
193
+ it { expect(Person).to act_as(Product) }
194
+ end
195
+
196
+ RSpec.describe "Product is actable" do
197
+ it { expect(Product).to be_actable }
198
+ end
199
+ ```
200
+
174
201
  ## Contributing
175
202
 
176
203
  1. Fork it ( https://github.com/hzamani/active_record-acts_as/fork )
@@ -9,6 +9,10 @@ module ActiveRecord
9
9
  @_reflections_acts_as_cache ||=
10
10
  _reflections_without_acts_as.reverse_merge(acting_as_model._reflections)
11
11
  end
12
+
13
+ def validators_on(*args)
14
+ super + acting_as_model.validators_on(*args)
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -20,6 +20,10 @@ module ActiveRecord
20
20
  !acting_as.id.nil? && !acting_as_foreign_key.nil?
21
21
  end
22
22
 
23
+ def touch_actable
24
+ acting_as.touch
25
+ end
26
+
23
27
  def actable_must_be_valid
24
28
  if validates_actable
25
29
  unless acting_as.valid?
@@ -0,0 +1,19 @@
1
+ RSpec::Matchers.define :act_as do |actable|
2
+ match do |actor|
3
+ if actor.is_a?(ActiveRecord::Base)
4
+ actor.class.acting_as?(actable)
5
+ else
6
+ actor.acting_as?(actable)
7
+ end
8
+ end
9
+ end
10
+
11
+ RSpec::Matchers.define :be_actable do
12
+ match do |actable|
13
+ if actable.is_a?(ActiveRecord::Base)
14
+ actable.class.actable?
15
+ else
16
+ actable.actable?
17
+ end
18
+ end
19
+ end
@@ -12,13 +12,15 @@ module ActiveRecord
12
12
  cattr_reader(:validates_actable) { options.delete(:validates_actable) == false ? false : true }
13
13
 
14
14
  reflections = has_one name, scope, options
15
- default_scope -> { eager_load(name) }
15
+ default_scope -> { includes(name) }
16
16
  validate :actable_must_be_valid
17
+ after_update :touch_actable
17
18
 
18
19
  cattr_reader(:acting_as_reflection) { reflections.stringify_keys[name.to_s] }
19
20
  cattr_reader(:acting_as_name) { name.to_s }
20
21
  cattr_reader(:acting_as_model) { (options[:class_name] || name.to_s.camelize).constantize }
21
- class_eval "def acting_as() #{name} || build_#{name} end"
22
+ class_eval "def #{name}; super || build_#{name} end"
23
+ alias_method :acting_as, name
22
24
  alias_method :acting_as=, "#{name}=".to_sym
23
25
 
24
26
  include ActsAs::InstanceMethods
@@ -1,6 +1,6 @@
1
-
2
1
  module ActiveRecord
3
2
  module ActsAs
4
- VERSION = "1.0.7"
3
+ VERSION = "1.0.8"
5
4
  end
6
5
  end
6
+
data/spec/acts_as_spec.rb CHANGED
@@ -16,6 +16,10 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
16
16
  expect(association.options).to have_key(:as)
17
17
  end
18
18
 
19
+ it "autobuilds the has_one relation" do
20
+ expect(subject.new.product).not_to be_nil
21
+ end
22
+
19
23
  it "has a cattr_reader for the acting_as_model" do
20
24
  expect(subject.acting_as_model).to eq Product
21
25
  end
@@ -139,6 +143,13 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
139
143
  end
140
144
  end
141
145
 
146
+ describe ".validators_on" do
147
+ it "merges the validations on both superclass and subclass" do
148
+ expect(Pen.validators_on(:name, :price)).to contain_exactly(
149
+ *Product.validators_on(:name, :price))
150
+ end
151
+ end
152
+
142
153
  describe "._reflections" do
143
154
  it "merges the reflections on both superclass and subclass" do
144
155
  expect(Pen._reflections.length).to eq(Product._reflections.length + 1)
@@ -181,7 +192,18 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
181
192
  isolated_pen.reload
182
193
  expect(pen.option1).to eq('value1')
183
194
  expect(isolated_pen).to_not respond_to('option1')
184
- expect(JSON.parse(pen.to_json)).to eq(JSON.parse('{"id":' + pen.id.to_s + ',"name":"pen","price":0.8,"store_id":null,"settings":{"global_option":"globalvalue","option1":"value1"},"color":"red"}'))
195
+ expect(JSON.parse(pen.to_json)).to eq(JSON.parse('''
196
+ {
197
+ "id": '+ pen.id.to_s + ',
198
+ "name": "pen",
199
+ "price": 0.8,
200
+ "store_id": null,
201
+ "settings": {"global_option":"globalvalue", "option1":"value1"},
202
+ "color": "red",
203
+ "created_at": ' + pen.created_at.to_json + ',
204
+ "updated_at": ' + pen.updated_at.to_json + '
205
+ }
206
+ '''))
185
207
  end
186
208
 
187
209
  it "saves supermodel attributes on save" do
@@ -192,6 +214,15 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
192
214
  expect(pen.color).to eq('red')
193
215
  end
194
216
 
217
+ it "touches supermodel on save" do
218
+ pen.save
219
+ pen.reload
220
+ update = pen.product.updated_at
221
+ pen.color = "gray"
222
+ pen.save
223
+ expect(pen.updated_at).not_to eq(update)
224
+ end
225
+
195
226
  it "raises NoMethodEror on unexisting method call" do
196
227
  expect { pen.unexisted_method }.to raise_error(NoMethodError)
197
228
  end
@@ -243,10 +274,22 @@ RSpec.describe "ActiveRecord::Base model with #acts_as called" do
243
274
  it "unless the submodel instance association doesn't exist" do
244
275
  expect(JSON.parse(isolated_pen.to_json)).to eq(JSON.parse('{"id":null,"color":"red"}'))
245
276
  end
277
+
246
278
  it "if the submodel instance association exists" do
247
279
  p = Product.new(name: 'Test Pen', price: 0.8, actable: pen)
248
280
  p.save
249
- expect(JSON.parse(pen.to_json)).to eq(JSON.parse('{"id":' + pen.id.to_s + ',"name":"pen","price":0.8,"store_id":null,"settings": {},"color":"red"}'))
281
+ expect(JSON.parse(pen.to_json)).to eq(JSON.parse('''
282
+ {
283
+ "id": '+ pen.id.to_s + ',
284
+ "name": "pen",
285
+ "price": 0.8,
286
+ "store_id": null,
287
+ "settings": {},
288
+ "color": "red",
289
+ "created_at": ' + pen.created_at.to_json + ',
290
+ "updated_at": ' + pen.updated_at.to_json + '
291
+ }
292
+ '''))
250
293
  end
251
294
  end
252
295
 
@@ -8,6 +8,7 @@ end
8
8
 
9
9
  RSpec.describe ".actable" do
10
10
  context "in .create_table block" do
11
+ after { initialize_schema }
11
12
  context "with :as options" do
12
13
  it "creates plymorphic reference columns with given name" do
13
14
  initialize_database { create_table(:products) { |t| t.actable(as: :produceable) } }
data/spec/models.rb CHANGED
@@ -54,30 +54,34 @@ module Inventory
54
54
  end
55
55
  end
56
56
 
57
- initialize_database do
58
- create_table :pens do |t|
59
- t.string :color
60
- end
57
+ def initialize_schema
58
+ initialize_database do
59
+ create_table :pens do |t|
60
+ t.string :color
61
+ end
61
62
 
62
- create_table :products do |t|
63
- t.string :name
64
- t.float :price
65
- t.integer :store_id
66
- t.text :settings
67
- t.actable
68
- end
63
+ create_table :products do |t|
64
+ t.string :name
65
+ t.float :price
66
+ t.integer :store_id
67
+ t.text :settings
68
+ t.timestamps null: true
69
+ t.actable
70
+ end
69
71
 
70
- create_table :stores do |t|
71
- t.string :name
72
- end
72
+ create_table :stores do |t|
73
+ t.string :name
74
+ end
73
75
 
74
- create_table :inventory_pen_lids do |t|
75
- t.string :color
76
- end
76
+ create_table :inventory_pen_lids do |t|
77
+ t.string :color
78
+ end
77
79
 
78
- create_table :inventory_product_features do |t|
79
- t.string :name
80
- t.float :price
81
- t.actable
80
+ create_table :inventory_product_features do |t|
81
+ t.string :name
82
+ t.float :price
83
+ t.actable
84
+ end
82
85
  end
83
86
  end
87
+ initialize_schema
@@ -0,0 +1,12 @@
1
+ require 'models'
2
+ require 'active_record/acts_as/matchers'
3
+
4
+ RSpec.describe "Custom RSpec matchers" do
5
+ it { expect(Product).to be_actable }
6
+ it { expect(Product.new).to be_actable }
7
+
8
+ it { expect(Pen).to act_as(:product) }
9
+ it { expect(Pen).to act_as(Product) }
10
+ it { expect(Pen.new).to act_as(:product) }
11
+ it { expect(Pen.new).to act_as(Product) }
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record-acts_as
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hassan Zamani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-21 00:00:00.000000000 Z
11
+ date: 2016-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -119,6 +119,7 @@ files:
119
119
  - lib/active_record/acts_as.rb
120
120
  - lib/active_record/acts_as/class_methods.rb
121
121
  - lib/active_record/acts_as/instance_methods.rb
122
+ - lib/active_record/acts_as/matchers.rb
122
123
  - lib/active_record/acts_as/migration.rb
123
124
  - lib/active_record/acts_as/querying.rb
124
125
  - lib/active_record/acts_as/relation.rb
@@ -129,6 +130,7 @@ files:
129
130
  - spec/database_helper.rb
130
131
  - spec/migrations_spec.rb
131
132
  - spec/models.rb
133
+ - spec/rspec_matchers_spec.rb
132
134
  - spec/spec_helper.rb
133
135
  homepage: http://github.com/hzamani/active_record-acts_as
134
136
  licenses:
@@ -150,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
152
  version: '0'
151
153
  requirements: []
152
154
  rubyforge_project:
153
- rubygems_version: 2.4.8
155
+ rubygems_version: 2.5.1
154
156
  signing_key:
155
157
  specification_version: 4
156
158
  summary: Simulate multi-table inheritance for activerecord models
@@ -161,4 +163,5 @@ test_files:
161
163
  - spec/database_helper.rb
162
164
  - spec/migrations_spec.rb
163
165
  - spec/models.rb
166
+ - spec/rspec_matchers_spec.rb
164
167
  - spec/spec_helper.rb