cistern 2.2.3 → 2.2.4
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 +4 -4
- data/.travis.yml +4 -4
- data/lib/cistern/attributes.rb +62 -61
- data/lib/cistern/client.rb +30 -24
- data/lib/cistern/collection.rb +15 -16
- data/lib/cistern/coverage.rb +7 -5
- data/lib/cistern/data/hash.rb +5 -7
- data/lib/cistern/data/redis.rb +7 -9
- data/lib/cistern/data.rb +2 -2
- data/lib/cistern/formatter/awesome_print.rb +1 -1
- data/lib/cistern/formatter/default.rb +2 -2
- data/lib/cistern/formatter/formatador.rb +3 -3
- data/lib/cistern/hash.rb +3 -3
- data/lib/cistern/mock.rb +2 -2
- data/lib/cistern/model.rb +10 -10
- data/lib/cistern/request.rb +2 -2
- data/lib/cistern/service.rb +2 -2
- data/lib/cistern/singular.rb +2 -5
- data/lib/cistern/string.rb +6 -6
- data/lib/cistern/timeout.rb +3 -3
- data/lib/cistern/version.rb +1 -1
- data/lib/cistern/wait_for.rb +4 -4
- data/lib/cistern.rb +5 -6
- data/spec/client_spec.rb +8 -9
- data/spec/collection_spec.rb +18 -18
- data/spec/dirty_spec.rb +9 -9
- data/spec/formatter_spec.rb +14 -14
- data/spec/hash_spec.rb +17 -17
- data/spec/mock_data_spec.rb +21 -22
- data/spec/model_spec.rb +76 -76
- data/spec/request_spec.rb +8 -8
- data/spec/singular_spec.rb +7 -8
- data/spec/spec_helper.rb +3 -3
- data/spec/wait_for_spec.rb +7 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12f0361fa92430b5aab7d1b3e8934a615670369a
|
4
|
+
data.tar.gz: 0a09ee7dd69399efbeb59a6341cbf6b18d7e55af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03c0726e4050c3c02fa05397625a43b651516dc1d7eea53166953dad89286212474ec880d74411ca44ff1d511c8cf17809116dc695831c118a02fe01fa3d4f01
|
7
|
+
data.tar.gz: d5149e6a0212522f9dae85f85b73ba1e699da5a06093a48b1ee5c5aa8733c43ee5855409c57c57ea6d24e940435b487c377eb7d0cb6d875d53fb999eea967c7f
|
data/.travis.yml
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 1.9
|
5
|
-
- jruby-19mode
|
3
|
+
- 2.2
|
4
|
+
- 1.9
|
6
5
|
bundler_args: "--without development"
|
7
6
|
before_install:
|
8
|
-
- gem install bundler -v 1.
|
7
|
+
- gem install bundler -v "~> 1.10"
|
9
8
|
script: bundle exec rake --trace
|
10
9
|
notifications:
|
11
10
|
email:
|
12
11
|
on_success: never
|
13
12
|
on_failure: change
|
13
|
+
sudo: false
|
14
14
|
services:
|
15
15
|
- redis-server
|
16
16
|
env:
|
data/lib/cistern/attributes.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
module Cistern::Attributes
|
2
2
|
def self.parsers
|
3
3
|
@parsers ||= {
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
4
|
+
string: ->(v, _) { v.to_s },
|
5
|
+
time: ->(v, _) { v.is_a?(Time) ? v : v && Time.parse(v.to_s) },
|
6
|
+
integer: ->(v, _) { v && v.to_i },
|
7
|
+
float: ->(v, _) { v && v.to_f },
|
8
|
+
array: ->(v, _) { [*v] },
|
9
|
+
boolean: ->(v, _) { %w(true 1).include?(v.to_s.downcase) }
|
10
10
|
}
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.transforms
|
14
14
|
@transforms ||= {
|
15
|
-
:
|
15
|
+
squash: proc do |_k, _v, options|
|
16
16
|
v = Cistern::Hash.stringify_keys(_v)
|
17
17
|
squash = options[:squash]
|
18
18
|
|
@@ -20,7 +20,8 @@ module Cistern::Attributes
|
|
20
20
|
travel = lambda do |tree, path|
|
21
21
|
if tree.is_a?(::Hash)
|
22
22
|
travel.call(tree[path.shift], path)
|
23
|
-
else
|
23
|
+
else
|
24
|
+
tree
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -30,7 +31,7 @@ module Cistern::Attributes
|
|
30
31
|
|
31
32
|
if v.key?(key = squash_s.to_sym)
|
32
33
|
v[key]
|
33
|
-
elsif v.
|
34
|
+
elsif v.key?(squash_s)
|
34
35
|
v[squash_s]
|
35
36
|
else
|
36
37
|
v
|
@@ -38,12 +39,12 @@ module Cistern::Attributes
|
|
38
39
|
else v
|
39
40
|
end
|
40
41
|
end,
|
41
|
-
:
|
42
|
+
none: ->(_, v, _) { v }
|
42
43
|
}
|
43
44
|
end
|
44
45
|
|
45
46
|
def self.default_parser
|
46
|
-
@default_parser ||=
|
47
|
+
@default_parser ||= ->(v, _opts) { v }
|
47
48
|
end
|
48
49
|
|
49
50
|
module ClassMethods
|
@@ -52,7 +53,7 @@ module Cistern::Attributes
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def aliases
|
55
|
-
@aliases ||= Hash.new { |h,k| h[k] = [] }
|
56
|
+
@aliases ||= Hash.new { |h, k| h[k] = [] }
|
56
57
|
end
|
57
58
|
|
58
59
|
def attributes
|
@@ -61,10 +62,10 @@ module Cistern::Attributes
|
|
61
62
|
|
62
63
|
def attribute(_name, options = {})
|
63
64
|
if defined? Cistern::Coverage
|
64
|
-
attribute_call = Cistern::Coverage.find_caller_before(
|
65
|
+
attribute_call = Cistern::Coverage.find_caller_before('cistern/attributes.rb')
|
65
66
|
|
66
67
|
# Only use DSL attribute calls from within a model
|
67
|
-
if attribute_call
|
68
|
+
if attribute_call && attribute_call.label.start_with?('<class:')
|
68
69
|
options[:coverage_file] = attribute_call.absolute_path
|
69
70
|
options[:coverage_line] = attribute_call.lineno
|
70
71
|
options[:coverage_hits] = 0
|
@@ -73,25 +74,23 @@ module Cistern::Attributes
|
|
73
74
|
|
74
75
|
name = _name.to_s.to_sym
|
75
76
|
|
76
|
-
|
77
|
+
send(:define_method, name) do
|
77
78
|
read_attribute(name)
|
78
|
-
end unless
|
79
|
+
end unless instance_methods.include?(name)
|
79
80
|
|
80
|
-
if options[:type] == :boolean
|
81
|
-
self.send(:alias_method, "#{name}?", name)
|
82
|
-
end
|
81
|
+
send(:alias_method, "#{name}?", name) if options[:type] == :boolean
|
83
82
|
|
84
|
-
|
83
|
+
send(:define_method, "#{name}=") do |value|
|
85
84
|
write_attribute(name, value)
|
86
|
-
end unless
|
85
|
+
end unless instance_methods.include?("#{name}=".to_sym)
|
87
86
|
|
88
|
-
if
|
89
|
-
|
87
|
+
if attributes[name]
|
88
|
+
fail(ArgumentError, "#{self.name} attribute[#{_name}] specified more than once")
|
90
89
|
else
|
91
90
|
if options[:squash]
|
92
91
|
options[:squash] = Array(options[:squash]).map(&:to_s)
|
93
92
|
end
|
94
|
-
|
93
|
+
attributes[name] = options
|
95
94
|
end
|
96
95
|
|
97
96
|
options[:aliases] = Array(options[:aliases] || options[:alias]).map { |a| a.to_s.to_sym }
|
@@ -103,7 +102,7 @@ module Cistern::Attributes
|
|
103
102
|
|
104
103
|
def identity(name, options = {})
|
105
104
|
@identity = name
|
106
|
-
|
105
|
+
attribute(name, options)
|
107
106
|
end
|
108
107
|
|
109
108
|
def ignore_attributes(*args)
|
@@ -116,33 +115,34 @@ module Cistern::Attributes
|
|
116
115
|
end
|
117
116
|
|
118
117
|
module InstanceMethods
|
119
|
-
def
|
118
|
+
def dump
|
120
119
|
Marshal.dump(attributes)
|
121
120
|
end
|
122
121
|
|
123
122
|
def read_attribute(name)
|
124
|
-
|
125
|
-
|
126
|
-
self.class.attributes[name.to_s.to_sym][:coverage_hits] += 1 rescue nil
|
127
|
-
|
123
|
+
key = name.to_s.to_sym
|
124
|
+
options = self.class.attributes[key]
|
128
125
|
default = options[:default]
|
129
126
|
|
130
|
-
|
131
|
-
|
127
|
+
# record the attribute was accessed
|
128
|
+
if defined?(Cistern::Coverage) && options[:coverage_hits]
|
129
|
+
options[:coverage_hits] += 1
|
132
130
|
end
|
133
131
|
|
134
|
-
|
132
|
+
default = Marshal.load(Marshal.dump(default)) unless default.nil?
|
133
|
+
|
134
|
+
attributes.fetch(key, default)
|
135
135
|
end
|
136
136
|
|
137
137
|
def write_attribute(name, value)
|
138
138
|
options = self.class.attributes[name] || {}
|
139
139
|
|
140
140
|
transform = Cistern::Attributes.transforms[options[:squash] ? :squash : :none] ||
|
141
|
-
|
141
|
+
Cistern::Attributes.default_transform
|
142
142
|
|
143
143
|
parser = Cistern::Attributes.parsers[options[:type]] ||
|
144
|
-
|
145
|
-
|
144
|
+
options[:parser] ||
|
145
|
+
Cistern::Attributes.default_parser
|
146
146
|
|
147
147
|
transformed = transform.call(name, value, options)
|
148
148
|
|
@@ -175,9 +175,7 @@ module Cistern::Attributes
|
|
175
175
|
def identity
|
176
176
|
key = self.class.instance_variable_get('@identity')
|
177
177
|
|
178
|
-
if key
|
179
|
-
public_send(key)
|
180
|
-
end
|
178
|
+
public_send(key) if key
|
181
179
|
end
|
182
180
|
|
183
181
|
def identity=(new_identity)
|
@@ -186,7 +184,7 @@ module Cistern::Attributes
|
|
186
184
|
if key
|
187
185
|
public_send("#{key}=", new_identity)
|
188
186
|
else
|
189
|
-
|
187
|
+
fail ArgumentError, 'Identity not specified'
|
190
188
|
end
|
191
189
|
end
|
192
190
|
|
@@ -197,37 +195,40 @@ module Cistern::Attributes
|
|
197
195
|
class_aliases = self.class.aliases
|
198
196
|
|
199
197
|
new_attributes.each do |_key, value|
|
200
|
-
string_key = _key.
|
198
|
+
string_key = _key.is_a?(String) ? _key : _key.to_s
|
201
199
|
symbol_key = case _key
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
200
|
+
when String
|
201
|
+
_key.to_sym
|
202
|
+
when Symbol
|
203
|
+
_key
|
204
|
+
else
|
205
|
+
string_key.to_sym
|
208
206
|
end
|
209
207
|
|
210
208
|
# find nested paths
|
211
209
|
value.is_a?(::Hash) && class_attributes.each do |name, options|
|
212
210
|
if options[:squash] && options[:squash].first == string_key
|
213
|
-
send("#{name}=",
|
211
|
+
send("#{name}=", symbol_key => value)
|
214
212
|
end
|
215
213
|
end
|
216
214
|
|
217
|
-
|
218
|
-
if class_aliases.has_key?(symbol_key)
|
219
|
-
class_aliases[symbol_key].each do |aliased_key|
|
220
|
-
send("#{aliased_key}=", value)
|
221
|
-
end
|
222
|
-
end
|
215
|
+
next if ignored_attributes.include?(symbol_key)
|
223
216
|
|
224
|
-
|
225
|
-
|
226
|
-
send(
|
217
|
+
if class_aliases.key?(symbol_key)
|
218
|
+
class_aliases[symbol_key].each do |aliased_key|
|
219
|
+
send("#{aliased_key}=", value)
|
227
220
|
end
|
228
221
|
end
|
222
|
+
|
223
|
+
assignment_method = "#{string_key}="
|
224
|
+
|
225
|
+
if !protected_methods.include?(symbol_key) && self.respond_to?(assignment_method, true)
|
226
|
+
send(assignment_method, value)
|
227
|
+
end
|
229
228
|
end
|
229
|
+
|
230
230
|
changed.clear
|
231
|
+
|
231
232
|
self
|
232
233
|
end
|
233
234
|
|
@@ -239,16 +240,16 @@ module Cistern::Attributes
|
|
239
240
|
def requires(*args)
|
240
241
|
missing = missing_attributes(args)
|
241
242
|
if missing.length == 1
|
242
|
-
|
243
|
+
fail(ArgumentError, "#{missing.first} is required for this operation")
|
243
244
|
elsif missing.any?
|
244
|
-
|
245
|
+
fail(ArgumentError, "#{missing[0...-1].join(', ')} and #{missing[-1]} are required for this operation")
|
245
246
|
end
|
246
247
|
end
|
247
248
|
|
248
249
|
def requires_one(*args)
|
249
250
|
missing = missing_attributes(args)
|
250
251
|
if missing.length == args.length
|
251
|
-
|
252
|
+
fail(ArgumentError, "#{missing[0...-1].join(', ')} or #{missing[-1]} are required for this operation")
|
252
253
|
end
|
253
254
|
end
|
254
255
|
|
@@ -257,7 +258,7 @@ module Cistern::Attributes
|
|
257
258
|
end
|
258
259
|
|
259
260
|
def dirty_attributes
|
260
|
-
changed.inject({}) { |r,(k,(_,v))| r.merge(k => v) }
|
261
|
+
changed.inject({}) { |r, (k, (_, v))| r.merge(k => v) }
|
261
262
|
end
|
262
263
|
|
263
264
|
def changed
|
data/lib/cistern/client.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Cistern::Client
|
2
|
-
|
3
2
|
module Collections
|
4
3
|
def collections
|
5
4
|
service.collections
|
@@ -11,7 +10,7 @@ module Cistern::Client
|
|
11
10
|
end
|
12
11
|
|
13
12
|
# custom include
|
14
|
-
def self.with(options={})
|
13
|
+
def self.with(options = {})
|
15
14
|
client_module = Module.new
|
16
15
|
|
17
16
|
custom_include = <<-EOS
|
@@ -29,22 +28,22 @@ module Cistern::Client
|
|
29
28
|
|
30
29
|
# vanilla include
|
31
30
|
def self.included(klass)
|
32
|
-
|
31
|
+
setup(klass)
|
33
32
|
|
34
33
|
super
|
35
34
|
end
|
36
35
|
|
37
|
-
def self.setup(klass, options={})
|
38
|
-
request_class = options[:request]
|
39
|
-
collection_class = options[:collection] ||
|
40
|
-
model_class = options[:model]
|
41
|
-
singular_class = options[:singular]
|
36
|
+
def self.setup(klass, options = {})
|
37
|
+
request_class = options[:request] || 'Request'
|
38
|
+
collection_class = options[:collection] || 'Collection'
|
39
|
+
model_class = options[:model] || 'Model'
|
40
|
+
singular_class = options[:singular] || 'Singular'
|
42
41
|
|
43
42
|
interface = options[:interface] || :class
|
44
43
|
interface_callback = (:class == interface) ? :inherited : :included
|
45
44
|
|
46
45
|
unless klass.name
|
47
|
-
|
46
|
+
fail ArgumentError, "can't turn anonymous class into a Cistern service"
|
48
47
|
end
|
49
48
|
|
50
49
|
klass.class_eval <<-EOS, __FILE__, __LINE__
|
@@ -156,10 +155,17 @@ module Cistern::Client
|
|
156
155
|
end
|
157
156
|
|
158
157
|
module ClassMethods
|
158
|
+
def mock!
|
159
|
+
@mocking = true
|
160
|
+
end
|
159
161
|
|
160
|
-
def
|
161
|
-
|
162
|
-
|
162
|
+
def mocking?
|
163
|
+
@mocking
|
164
|
+
end
|
165
|
+
|
166
|
+
def unmock!
|
167
|
+
@mocking = false
|
168
|
+
end
|
163
169
|
|
164
170
|
def collections
|
165
171
|
@collections ||= []
|
@@ -186,26 +192,26 @@ module Cistern::Client
|
|
186
192
|
end
|
187
193
|
|
188
194
|
def requires(*args)
|
189
|
-
|
195
|
+
required_arguments.concat(args)
|
190
196
|
end
|
191
197
|
|
192
198
|
def recognizes(*args)
|
193
|
-
|
199
|
+
recognized_arguments.concat(args)
|
194
200
|
end
|
195
201
|
|
196
|
-
def validate_options(options={})
|
202
|
+
def validate_options(options = {})
|
197
203
|
required_options = Cistern::Hash.slice(options, *required_arguments)
|
198
204
|
|
199
205
|
missing_required_options = required_arguments - required_options.keys
|
200
206
|
|
201
207
|
unless missing_required_options.empty?
|
202
|
-
|
208
|
+
fail "Missing required options: #{missing_required_options.inspect}"
|
203
209
|
end
|
204
210
|
|
205
211
|
unrecognized_options = options.keys - (required_arguments + recognized_arguments)
|
206
212
|
|
207
213
|
unless unrecognized_options.empty?
|
208
|
-
|
214
|
+
fail "Unrecognized options: #{unrecognized_options.inspect}"
|
209
215
|
end
|
210
216
|
end
|
211
217
|
|
@@ -214,28 +220,28 @@ module Cistern::Client
|
|
214
220
|
|
215
221
|
requests.each do |klass|
|
216
222
|
name = klass.service_method ||
|
217
|
-
|
223
|
+
Cistern::String.camelize(Cistern::String.demodulize(klass.name))
|
218
224
|
|
219
225
|
Cistern::Request.service_request(self, klass, name)
|
220
226
|
end
|
221
227
|
|
222
228
|
collections.each do |klass|
|
223
229
|
name = klass.service_method ||
|
224
|
-
|
230
|
+
Cistern::String.underscore(klass.name.gsub("#{self.name}::", '').gsub('::', ''))
|
225
231
|
|
226
232
|
Cistern::Collection.service_collection(self, klass, name)
|
227
233
|
end
|
228
234
|
|
229
235
|
models.each do |klass|
|
230
236
|
name = klass.service_method ||
|
231
|
-
|
237
|
+
Cistern::String.underscore(klass.name.gsub("#{self.name}::", '').gsub('::', ''))
|
232
238
|
|
233
239
|
Cistern::Model.service_model(self, klass, name)
|
234
240
|
end
|
235
241
|
|
236
242
|
singularities.each do |klass|
|
237
243
|
name = klass.service_method ||
|
238
|
-
|
244
|
+
Cistern::String.underscore(klass.name.gsub("#{self.name}::", '').gsub('::', ''))
|
239
245
|
|
240
246
|
Cistern::Singular.service_singular(self, klass, name)
|
241
247
|
end
|
@@ -243,15 +249,15 @@ module Cistern::Client
|
|
243
249
|
@_setup = true
|
244
250
|
end
|
245
251
|
|
246
|
-
def new(options={})
|
252
|
+
def new(options = {})
|
247
253
|
setup
|
248
254
|
validate_options(options)
|
249
255
|
|
250
|
-
|
256
|
+
const_get(self.mocking? ? :Mock : :Real).new(options)
|
251
257
|
end
|
252
258
|
|
253
259
|
def reset!
|
254
|
-
|
260
|
+
const_get(:Mock).reset!
|
255
261
|
end
|
256
262
|
end
|
257
263
|
end
|