cistern 2.2.3 → 2.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|