api_hammer 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Rakefile.rb +2 -1
- data/lib/api_hammer/active_record_cache_find_by.rb +135 -0
- data/lib/api_hammer/version.rb +1 -1
- data/test/active_record_cache_find_by_test.rb +201 -0
- data/test/halt_test.rb +2 -4
- data/test/helper.rb +4 -0
- metadata +47 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9927a5896d97412a1668d60c7f341649cca1232c
|
4
|
+
data.tar.gz: 0d65a4cf1399613c3f1433f0a456f88ae1cf9008
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f1fdf86e116a112eee8a09420b62d356ce66ac8522e41ef30470862ed7c29491e0cbe7fa02e5fe7b63bb834887d572a68feeeb5fc9ab5eede0db6ddebe3e95c
|
7
|
+
data.tar.gz: 51a41edd33b376e0d2cc9e49ff86fa0d60afa7cb8dbda2d4ebac12b10f64c300002813db33f79d7f914d52a9f9636f87c11bea584aa06fcf081705b81e96ecb6
|
data/CHANGELOG.md
CHANGED
data/Rakefile.rb
CHANGED
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Relation
|
5
|
+
if !method_defined?(:first_without_caching)
|
6
|
+
alias_method :first_without_caching, :first
|
7
|
+
def first(*args)
|
8
|
+
one_record_with_caching(args.empty?) { first_without_caching(*args) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
if !method_defined?(:take_without_caching) && method_defined?(:take)
|
12
|
+
alias_method :take_without_caching, :take
|
13
|
+
def take(*args)
|
14
|
+
one_record_with_caching(args.empty?) { take_without_caching(*args) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# retrieves one record, hitting the cache if appropriate. the argument may bypass caching
|
19
|
+
# (the caller could elect to just not call this method if caching is to be avoided, but since this
|
20
|
+
# method already builds in opting whether or not to hit cache, the code is simpler just passing that in).
|
21
|
+
#
|
22
|
+
# requires a block which returns the record
|
23
|
+
def one_record_with_caching(can_cache = true)
|
24
|
+
actual_right = proc do |where_value|
|
25
|
+
if where_value.right.is_a?(Arel::Nodes::BindParam)
|
26
|
+
column, value = bind_values.detect { |(column, value)| column.name == where_value.left.name }
|
27
|
+
value
|
28
|
+
else
|
29
|
+
where_value.right
|
30
|
+
end
|
31
|
+
end
|
32
|
+
cache_find_bys = klass.send(:cache_find_bys)
|
33
|
+
can_cache &&= cache_find_bys &&
|
34
|
+
!loaded? && # if it's loaded no need to hit cache
|
35
|
+
where_values.all? { |wv| wv.is_a?(Arel::Nodes::Equality) } && # no inequality or that sort of thing
|
36
|
+
cache_find_bys.include?(where_values.map { |wv| wv.left.name }.sort) && # any of the set of where-values to cache match this relation
|
37
|
+
where_values.map(&actual_right).all? { |r| r.is_a?(String) || r.is_a?(Numeric) } && # check all right side values are simple types, number or string
|
38
|
+
offset_value.nil? &&
|
39
|
+
joins_values.blank? &&
|
40
|
+
order_values.blank? &&
|
41
|
+
!reverse_order_value &&
|
42
|
+
includes_values.blank? &&
|
43
|
+
preload_values.blank? &&
|
44
|
+
select_values.blank? &&
|
45
|
+
group_values.blank? &&
|
46
|
+
from_value.nil? &&
|
47
|
+
lock_value.nil?
|
48
|
+
|
49
|
+
if can_cache
|
50
|
+
cache_key = klass.send(:cache_key_for, where_values.map { |wv| [wv.left.name, actual_right.call(wv)] })
|
51
|
+
klass.finder_cache.fetch(cache_key) do
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
else
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Base
|
61
|
+
class << self
|
62
|
+
def finder_cache=(val)
|
63
|
+
define_singleton_method(:finder_cache) { val }
|
64
|
+
end
|
65
|
+
|
66
|
+
# the cache. should be an instance of some sort of ActiveSupport::Cache::Store.
|
67
|
+
# by default uses Rails.cache if that exists, or creates a ActiveSupport::Cache::MemoryStore to use.
|
68
|
+
# set this per-model or on ActiveRecord::Base, as needed; it is inherited.
|
69
|
+
def finder_cache
|
70
|
+
# dummy; this gets set below
|
71
|
+
end
|
72
|
+
|
73
|
+
# causes requests to retrieve a record by the given attributes (all of them) to be cached.
|
74
|
+
# this is for single records only. it is unsafe to use with a set of attributes whose values
|
75
|
+
# (in conjunction) may be associated with multiple records.
|
76
|
+
#
|
77
|
+
# see .finder_cache and .find_cache= for where it is cached.
|
78
|
+
#
|
79
|
+
# #flush_find_cache is defined on the instance. it is called on save to clear an updated record from
|
80
|
+
# the cache. it may also be called explicitly to clear a record from the cache.
|
81
|
+
#
|
82
|
+
# beware of multiple application servers with different caches - a record cached in multiple will not
|
83
|
+
# be invalidated in all when it is saved in one.
|
84
|
+
def cache_find_by(*attribute_names)
|
85
|
+
unless cache_find_bys
|
86
|
+
# initial setup
|
87
|
+
self.cache_find_bys = Set.new
|
88
|
+
after_update :flush_find_cache
|
89
|
+
before_destroy :flush_find_cache
|
90
|
+
end
|
91
|
+
|
92
|
+
find_by = attribute_names.map do |name|
|
93
|
+
raise(ArgumentError) unless name.is_a?(Symbol) || name.is_a?(String)
|
94
|
+
name.to_s.dup.freeze
|
95
|
+
end.sort.freeze
|
96
|
+
|
97
|
+
self.cache_find_bys = (cache_find_bys | [find_by]).freeze
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def cache_find_bys=(val)
|
102
|
+
define_singleton_method(:cache_find_bys) { val }
|
103
|
+
singleton_class.send(:private, :cache_find_bys)
|
104
|
+
end
|
105
|
+
|
106
|
+
def cache_find_bys
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def cache_key_for(find_attributes)
|
111
|
+
attrs = find_attributes.map { |k,v| [k.to_s, v.to_s] }.sort_by(&:first).inject([], &:+)
|
112
|
+
cache_key_prefix = ['cache_find_by', table_name]
|
113
|
+
@parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
114
|
+
cache_key = (cache_key_prefix + attrs).map do |part|
|
115
|
+
@parser.escape(part, /[^a-z0-9\-\.\_\~]/i)
|
116
|
+
end.join('/')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# the above dummy method has no content because we want to evaluate this now, not in the method, to
|
121
|
+
# avoid instantiating duplicate MemoryStores.
|
122
|
+
self.finder_cache = (Object.const_defined?(:Rails) && ::Rails.cache) || ::ActiveSupport::Cache::MemoryStore.new
|
123
|
+
|
124
|
+
# clears this record from the cache used by cache_find_by
|
125
|
+
def flush_find_cache
|
126
|
+
self.class.send(:cache_find_bys).each do |attribute_names|
|
127
|
+
find_attributes = attribute_names.map { |attr_name| [attr_name, attribute_was(attr_name)] }
|
128
|
+
self.class.instance_exec(find_attributes) do |find_attributes|
|
129
|
+
finder_cache.delete(cache_key_for(find_attributes))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/api_hammer/version.rb
CHANGED
@@ -0,0 +1,201 @@
|
|
1
|
+
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
require 'active_support/cache'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection(
|
8
|
+
:adapter => "sqlite3",
|
9
|
+
:database => ":memory:"
|
10
|
+
)
|
11
|
+
|
12
|
+
module Rails
|
13
|
+
class << self
|
14
|
+
def cache
|
15
|
+
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'api_hammer/active_record_cache_find_by'
|
21
|
+
|
22
|
+
ActiveRecord::Schema.define do
|
23
|
+
create_table :albums do |table|
|
24
|
+
table.column :title, :string
|
25
|
+
table.column :performer, :string
|
26
|
+
table.column :tracks, :integer
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Album < ActiveRecord::Base
|
31
|
+
cache_find_by(:id)
|
32
|
+
cache_find_by(:performer)
|
33
|
+
cache_find_by(:title, :performer)
|
34
|
+
cache_find_by(:tracks)
|
35
|
+
end
|
36
|
+
|
37
|
+
class VinylAlbum < Album
|
38
|
+
self.finder_cache = ActiveSupport::Cache::MemoryStore.new
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'ActiveRecord::Base.cache_find_by' do
|
42
|
+
def assert_caches(key, cache = Rails.cache)
|
43
|
+
assert !cache.read(key), "cache already contains a key #{key}: #{cache.read(key)}"
|
44
|
+
yield
|
45
|
+
ensure
|
46
|
+
assert cache.read(key), "key #{key} was not cached"
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_not_caches(key, cache = Rails.cache)
|
50
|
+
assert !cache.read(key), "cache already contains a key #{key}: #{cache.read(key)}"
|
51
|
+
yield
|
52
|
+
ensure
|
53
|
+
assert !cache.read(key), "key was incorrectly cached - #{key}: #{cache.read(key)}"
|
54
|
+
end
|
55
|
+
|
56
|
+
after do
|
57
|
+
Album.all.each(&:destroy)
|
58
|
+
end
|
59
|
+
|
60
|
+
it('caches #find by primary key') do
|
61
|
+
id = Album.create!.id
|
62
|
+
assert_caches("cache_find_by/albums/id/#{id}") { assert Album.find(id) }
|
63
|
+
end
|
64
|
+
|
65
|
+
it('caches #find_by_id') do
|
66
|
+
id = Album.create!.id
|
67
|
+
assert_caches("cache_find_by/albums/id/#{id}") { assert Album.find_by_id(id) }
|
68
|
+
end
|
69
|
+
|
70
|
+
it('caches #where.first with primary key') do
|
71
|
+
id = Album.create!.id
|
72
|
+
assert_caches("cache_find_by/albums/id/#{id}") { assert Album.where(:id => id).first }
|
73
|
+
end
|
74
|
+
|
75
|
+
it('caches find_by_x with one attribute') do
|
76
|
+
Album.create!(:performer => 'x')
|
77
|
+
assert_caches("cache_find_by/albums/performer/x") { assert Album.find_by_performer('x') }
|
78
|
+
end
|
79
|
+
|
80
|
+
it('caches find_by_x! with one attribute') do
|
81
|
+
Album.create!(:performer => 'x')
|
82
|
+
assert_caches("cache_find_by/albums/performer/x") { assert Album.find_by_performer!('x') }
|
83
|
+
end
|
84
|
+
|
85
|
+
it('caches where.first with one attribute') do
|
86
|
+
Album.create!(:performer => 'x')
|
87
|
+
assert_caches("cache_find_by/albums/performer/x") { assert Album.where(:performer => 'x').first }
|
88
|
+
end
|
89
|
+
|
90
|
+
it('caches where.first! with one attribute') do
|
91
|
+
Album.create!(:performer => 'x')
|
92
|
+
assert_caches("cache_find_by/albums/performer/x") { assert Album.where(:performer => 'x').first! }
|
93
|
+
end
|
94
|
+
|
95
|
+
it('caches #where.first with integer attribute') do
|
96
|
+
id = Album.create!(:tracks => 3).id
|
97
|
+
assert_caches("cache_find_by/albums/tracks/3") { assert Album.where(:tracks => 3).first }
|
98
|
+
end
|
99
|
+
|
100
|
+
it('does not cache #where.first with inequality of integer attribute') do
|
101
|
+
id = Album.create!(:tracks => 3).id
|
102
|
+
assert_not_caches("cache_find_by/albums/tracks/3") { assert Album.where(Album.arel_table['tracks'].gteq(3)).first }
|
103
|
+
end
|
104
|
+
|
105
|
+
if ActiveRecord::Relation.method_defined?(:take)
|
106
|
+
it('caches where.take with one attribute') do
|
107
|
+
Album.create!(:performer => 'x')
|
108
|
+
assert_caches("cache_find_by/albums/performer/x") { assert Album.where(:performer => 'x').take }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it('does not cache where.last with one attribute') do
|
113
|
+
Album.create!(:performer => 'x')
|
114
|
+
assert_not_caches("cache_find_by/albums/performer/x") { assert Album.where(:performer => 'x').last }
|
115
|
+
end
|
116
|
+
|
117
|
+
it('does not cache find with array') do
|
118
|
+
ids = [Album.create!.id, Album.create!.id]
|
119
|
+
assert_not_caches("cache_find_by/albums/id/#{ids.first}") { assert Album.find(ids) }
|
120
|
+
end
|
121
|
+
|
122
|
+
it('does not cache find_by_x with array') do
|
123
|
+
ids = [Album.create!.id, Album.create!.id]
|
124
|
+
assert_not_caches("cache_find_by/albums/id/#{ids.first}") { assert Album.find_by_id(ids) }
|
125
|
+
end
|
126
|
+
|
127
|
+
it('does not cache where.first with array') do
|
128
|
+
ids = [Album.create!.id, Album.create!.id]
|
129
|
+
assert_not_caches("cache_find_by/albums/id/#{ids.first}") { assert Album.where(:id => ids).first }
|
130
|
+
end
|
131
|
+
|
132
|
+
it('does not cache find_by_x with one attribute') do
|
133
|
+
Album.create!(:title => 'x')
|
134
|
+
assert_not_caches("cache_find_by/albums/title/x") { assert Album.find_by_title('x') }
|
135
|
+
end
|
136
|
+
|
137
|
+
it('does not cache where.first with one attribute') do
|
138
|
+
Album.create!(:title => 'x')
|
139
|
+
assert_not_caches("cache_find_by/albums/title/x") { assert Album.where(:title => 'x').first }
|
140
|
+
end
|
141
|
+
|
142
|
+
it('caches find_by_x with two attributes') do
|
143
|
+
Album.create!(:title => 'x', :performer => 'y')
|
144
|
+
assert_caches("cache_find_by/albums/performer/y/title/x") { assert Album.find_by_title_and_performer('x', 'y') }
|
145
|
+
end
|
146
|
+
|
147
|
+
it('caches where.first with two attributes') do
|
148
|
+
Album.create!(:title => 'x', :performer => 'y')
|
149
|
+
assert_caches("cache_find_by/albums/performer/y/title/x") { assert Album.where(:title => 'x', :performer => 'y').first }
|
150
|
+
end
|
151
|
+
|
152
|
+
it('flushes cache on save') do
|
153
|
+
album = Album.create!(:title => 'x', :performer => 'y')
|
154
|
+
assert_caches(key1 = "cache_find_by/albums/performer/y/title/x") { assert Album.find_by_title_and_performer('x', 'y') }
|
155
|
+
assert_caches(key2 = "cache_find_by/albums/performer/y") { assert Album.find_by_performer('y') }
|
156
|
+
album.update_attributes!(:performer => 'z')
|
157
|
+
assert !Rails.cache.read(key1), Rails.cache.instance_eval { @data }.inspect
|
158
|
+
assert !Rails.cache.read(key2), Rails.cache.instance_eval { @data }.inspect
|
159
|
+
end
|
160
|
+
|
161
|
+
it('flushes cache on destroy') do
|
162
|
+
album = Album.create!(:title => 'x', :performer => 'y')
|
163
|
+
assert_caches(key1 = "cache_find_by/albums/performer/y/title/x") { assert Album.find_by_title_and_performer('x', 'y') }
|
164
|
+
assert_caches(key2 = "cache_find_by/albums/performer/y") { assert Album.find_by_performer('y') }
|
165
|
+
album.destroy
|
166
|
+
assert !Rails.cache.read(key1), Rails.cache.instance_eval { @data }.inspect
|
167
|
+
assert !Rails.cache.read(key2), Rails.cache.instance_eval { @data }.inspect
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'inherits cache_find_bys' do
|
171
|
+
assert VinylAlbum.send(:cache_find_bys).any? { |f| f == ['id'] }
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'uses a different cache when specified' do
|
175
|
+
assert Album.finder_cache != VinylAlbum.finder_cache
|
176
|
+
|
177
|
+
id = Album.create!.id
|
178
|
+
key = "cache_find_by/albums/id/#{id}"
|
179
|
+
assert_caches(key) do
|
180
|
+
assert_not_caches(key, VinylAlbum.finder_cache) do
|
181
|
+
assert Album.find(id)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
id = VinylAlbum.create!.id
|
186
|
+
key = "cache_find_by/albums/id/#{id}"
|
187
|
+
assert_caches(key, VinylAlbum.finder_cache) do
|
188
|
+
assert_not_caches(key) do
|
189
|
+
assert VinylAlbum.find(id)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'does not get confused by values with slashes' do
|
195
|
+
Album.create!(:title => 'z', :performer => 'y/title/x')
|
196
|
+
Album.create!(:title => 'x', :performer => 'y')
|
197
|
+
|
198
|
+
Album.where(:performer => 'y', :title => 'x').first
|
199
|
+
assert_equal 'z', Album.where(:performer => 'y/title/x').first.title
|
200
|
+
end
|
201
|
+
end
|
data/test/halt_test.rb
CHANGED
@@ -36,10 +36,8 @@ describe 'ApiHammer::Rails#halt' do
|
|
36
36
|
it 'returns a record if it exists' do
|
37
37
|
record = Object.new
|
38
38
|
model = Class.new do
|
39
|
-
(
|
40
|
-
|
41
|
-
define_method(:table_name) { 'records' }
|
42
|
-
end
|
39
|
+
define_singleton_method(:where) { |attrs| [record] }
|
40
|
+
define_singleton_method(:table_name) { 'records' }
|
43
41
|
end
|
44
42
|
assert_equal record, FakeController.new.find_or_halt(model, {:id => 'anid'})
|
45
43
|
end
|
data/test/helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('../lib', File.dirname(__FILE__)))
|
2
2
|
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup
|
5
|
+
|
3
6
|
require 'simplecov'
|
7
|
+
require 'byebug'
|
4
8
|
|
5
9
|
# NO EXPECTATIONS
|
6
10
|
ENV["MT_NO_EXPECTATIONS"] = ''
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_hammer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ethan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -164,6 +164,48 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: activesupport
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: activerecord
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: sqlite3
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
167
209
|
description: actually a set of small API-related tools. very much unlike a hammer
|
168
210
|
at all, which is one large tool.
|
169
211
|
email:
|
@@ -181,6 +223,7 @@ files:
|
|
181
223
|
- Rakefile.rb
|
182
224
|
- bin/hc
|
183
225
|
- lib/api_hammer.rb
|
226
|
+
- lib/api_hammer/active_record_cache_find_by.rb
|
184
227
|
- lib/api_hammer/check_required_params.rb
|
185
228
|
- lib/api_hammer/faraday/outputter.rb
|
186
229
|
- lib/api_hammer/halt.rb
|
@@ -196,6 +239,7 @@ files:
|
|
196
239
|
- lib/api_hammer/unmunged_request_params.rb
|
197
240
|
- lib/api_hammer/version.rb
|
198
241
|
- lib/api_hammer/weblink.rb
|
242
|
+
- test/active_record_cache_find_by_test.rb
|
199
243
|
- test/check_required_params_test.rb
|
200
244
|
- test/halt_test.rb
|
201
245
|
- test/helper.rb
|
@@ -229,6 +273,7 @@ signing_key:
|
|
229
273
|
specification_version: 4
|
230
274
|
summary: an API tool
|
231
275
|
test_files:
|
276
|
+
- test/active_record_cache_find_by_test.rb
|
232
277
|
- test/check_required_params_test.rb
|
233
278
|
- test/halt_test.rb
|
234
279
|
- test/helper.rb
|