active_record_block_matchers 0.2.0 → 0.2.1

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: 56549819eb77b8a9e445755d2ed4d66c8a7c78d7
4
- data.tar.gz: 5eae4e2fbe09eff5486f783ff296b437b92c84bd
3
+ metadata.gz: eeeaef70749a55d2326e700d7c5bfbb00f15101a
4
+ data.tar.gz: 5ab0c836a3c6f8bdf0be53aaf20bcd57f748a949
5
5
  SHA512:
6
- metadata.gz: a8702eb8afc69876c8b15bb624124de2aae8c0735e8c05a9f6faf67fc7cf470c3163e2332c1fee2faf6c97dec8d7a3d8695e74e0264f550eaa465e87ab210316
7
- data.tar.gz: 4f957401eac7b5b596bf04dbe6a402f2ba0c88d12facf8e7f017c29ba1bee72b410de8834dc1f3e4c2ac9849664f761aba6b77ce88122b946320d1967965363b
6
+ metadata.gz: 395c2b2dbbdc5629545b800f174d03153509f58e700e3954f630d0c016cb343f70ca3cb0b43a25965db3b558e1e88c1e2addb254378043c7fcbd81092c024973
7
+ data.tar.gz: 9c8bb147aabcfa50531cbbf40d50e2be7cae215e10a071eff716c88f21a8ff2d06ceaeb0abea7ef4e535868acdb8c59bee99070d4a23c600b68c5560bd1176c6
data/README.md CHANGED
@@ -98,8 +98,6 @@ expect { User.create!(username: "BOB", password: "BlueSteel45") }
98
98
 
99
99
  **Gotcha Warning:** Be careful about your block syntax when chaining `.which` in your tests. If you write the above example with a `do...end`, the example will parse like this: `expect {...}.to(create_a(User).which) do |user| ... end`, so your block will not execute, and it may appear that your test is passing, when it is not.
100
100
 
101
- This matcher relies on a `created_at` column existing on the given model class. The name of this column can be configured via `ActiveRecordBlockMatchers::Config.created_at_column_name = "your_column_name"`
102
-
103
101
  #### `create`
104
102
 
105
103
  aliases: `create_records`
@@ -156,6 +154,40 @@ expect { User.create!(username: "bob"); User.create!(username: "rhonda") }
156
154
  )
157
155
  ```
158
156
 
157
+ ## Record Retrieval Strategies
158
+
159
+ There are currently two retrieval strategies implemented: `:id` and `:timestamp`. `:id` is the default, but this can be configured via the `default_strategy` configuration variable (more details [below](#configuration)).
160
+
161
+ The ID and Timestamp Strategies work similarly. The ID Strategy queries the appropriate table(s) to find the highest ID value(s) before the block, then finds new records by looking for records with an ID that higher than that. The Timestamp Strategy uses `Time.current` to record the time before the block. Then it finds new records by looking for records that have a timestamp later than that.
162
+
163
+ The ID Strategy is the default because it doesn't rely on time values that may be imprecise or mocked out. The Timestamp Strategy is useful if your tables don't have autoincrementing integer primary keys.
164
+
165
+ ## Configuration
166
+
167
+ You can configure the column names used by the ID or Timestamp Strategies. Put code like this in your `spec_helper.rb` or similar file:
168
+
169
+ ```ruby
170
+ ActiveRecordBlockMatchers.configure do |config|
171
+
172
+ # default value is "id"
173
+ config.id_column_name = "primary_key"
174
+
175
+ # default value is "created_at"
176
+ config.created_at_column_name = "created_timestamp"
177
+
178
+ # default value is :id
179
+ # must be one of [:id, :timestamp]
180
+ config.default_strategy = :timestamp
181
+ end
182
+ ```
183
+
184
+ You can also override the default strategy for individual assertions if needed:
185
+
186
+ ```ruby
187
+ Timecop.freeze
188
+ expect { Person.create! }.to create_a(Person, strategy: :id)
189
+ ```
190
+
159
191
 
160
192
  ## Development
161
193
 
@@ -28,5 +28,6 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "rspec", "~> 3.2"
29
29
  spec.add_development_dependency "pry", "~> 0.10.1"
30
30
  spec.add_development_dependency "sqlite3", "~> 1.3.10"
31
+ spec.add_development_dependency "database_cleaner", "~> 1.5.1"
31
32
  spec.add_development_dependency "standalone_migrations", "~> 2.1.5"
32
33
  end
@@ -1,6 +1,18 @@
1
1
  module ActiveRecordBlockMatchers
2
2
  class Config
3
3
 
4
+ def self.configure
5
+ yield self
6
+ end
7
+
8
+ def self.default_strategy
9
+ @default_strategy || :id
10
+ end
11
+
12
+ def self.default_strategy=(strategy_key)
13
+ @default_strategy = strategy_key.to_sym
14
+ end
15
+
4
16
  def self.created_at_column_name
5
17
  @created_at_column_name || "created_at"
6
18
  end
@@ -8,5 +20,13 @@ module ActiveRecordBlockMatchers
8
20
  def self.created_at_column_name=(column_name)
9
21
  @created_at_column_name = column_name
10
22
  end
23
+
24
+ def self.id_column_name
25
+ @id_column_name || "id"
26
+ end
27
+
28
+ def self.id_column_name=(column_name)
29
+ @id_column_name = column_name
30
+ end
11
31
  end
12
32
  end
@@ -13,14 +13,13 @@ RSpec::Matchers.define :create_a_new do |klass|
13
13
  @which_block = block
14
14
  end
15
15
 
16
- match do |block|
17
- time_before = Time.current
16
+ match do |options={}, block|
17
+ fetching_strategy =
18
+ ActiveRecordBlockMatchers::Strategies.for_key(options[:strategy]).new(block)
18
19
 
19
- block.call
20
+ @created_records = fetching_strategy.new_records([klass])[klass]
20
21
 
21
- column_name = ActiveRecordBlockMatchers::Config.created_at_column_name
22
- @created_records = klass.where("#{column_name} > ?", time_before)
23
- return false unless @created_records.count == 1
22
+ return false unless @created_records.count == 1 # ? this shouldn't be necessary for all strategies...
24
23
 
25
24
  record = @created_records.first
26
25
 
@@ -20,16 +20,11 @@ RSpec::Matchers.define :create_records do |record_counts|
20
20
  @which_block = block
21
21
  end
22
22
 
23
- match do |block|
24
- time_before = Time.current
23
+ match do |options={}, block|
24
+ fetching_strategy =
25
+ ActiveRecordBlockMatchers::Strategies.for_key(options[:strategy]).new(block)
25
26
 
26
- block.call
27
-
28
- @new_records =
29
- record_counts.keys.each_with_object({}) do |klass, new_records|
30
- column_name = ActiveRecordBlockMatchers::Config.created_at_column_name
31
- new_records[klass] = klass.where("#{column_name} > ?", time_before).to_a
32
- end
27
+ @new_records = fetching_strategy.new_records(record_counts.keys)
33
28
 
34
29
  @incorrect_counts =
35
30
  @new_records.each_with_object({}) do |(klass, new_records), incorrect|
@@ -0,0 +1,31 @@
1
+ module ActiveRecordBlockMatchers
2
+ class Strategies
3
+
4
+ def self.all_strategies
5
+ @all_strategies ||= {
6
+ id: IdStrategy,
7
+ timestamp: TimestampStrategy,
8
+ }
9
+ end
10
+
11
+ def self.default
12
+ get_strategy!(Config.default_strategy)
13
+ end
14
+
15
+ def self.for_key(strategy_key)
16
+ if strategy_key.nil?
17
+ default
18
+ else
19
+ get_strategy!(strategy_key)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def self.get_strategy!(strategy_key)
26
+ all_strategies.fetch(strategy_key)
27
+ rescue KeyError
28
+ raise UnknownStrategyError, "#{strategy_key.inspect} is not a known strategy (known strategies are #{all_strategies.keys})"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveRecordBlockMatchers
2
+ class IdStrategy
3
+
4
+ def initialize(block)
5
+ @block = block
6
+ end
7
+
8
+ def new_records(classes)
9
+ ids_before = classes.each_with_object({}) do |klass, ids_before|
10
+ ids_before[klass] = klass.select("MAX(#{column_name}) as max_id").first.try(:max_id) || 0
11
+ end
12
+
13
+ block.call
14
+
15
+ classes.each_with_object({}) do |klass, new_records|
16
+ id_before = ids_before[klass]
17
+ new_records[klass] = klass.where("#{column_name} > ?", id_before).to_a
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :block
24
+
25
+ def column_name
26
+ @column_name ||= ActiveRecordBlockMatchers::Config.id_column_name
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveRecordBlockMatchers
2
+ class TimestampStrategy
3
+
4
+ def initialize(block)
5
+ @block = block
6
+ end
7
+
8
+ def new_records(classes)
9
+ time_before = Time.current
10
+
11
+ block.call
12
+
13
+ classes.each_with_object({}) do |klass, new_records|
14
+ new_records[klass] = klass.where("#{column_name} > ?", time_before).to_a
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :block
21
+
22
+ def column_name
23
+ @column_name ||= ActiveRecordBlockMatchers::Config.created_at_column_name
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordBlockMatchers
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_block_matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Wallace
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-06 00:00:00.000000000 Z
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.3.10
111
+ - !ruby/object:Gem::Dependency
112
+ name: database_cleaner
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.5.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.5.1
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: standalone_migrations
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -148,6 +162,9 @@ files:
148
162
  - lib/active_record_block_matchers/config.rb
149
163
  - lib/active_record_block_matchers/create_a_new_matcher.rb
150
164
  - lib/active_record_block_matchers/create_records_matcher.rb
165
+ - lib/active_record_block_matchers/strategies.rb
166
+ - lib/active_record_block_matchers/strategies/id_strategy.rb
167
+ - lib/active_record_block_matchers/strategies/timestamp_strategy.rb
151
168
  - lib/active_record_block_matchers/version.rb
152
169
  homepage: https://github.com/nwallace/active_record_block_matchers
153
170
  licenses: