cistern 0.12.3 → 1.0.0.pre

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: 4f214af97e02bf01188735dc497174c917a65c8f
4
- data.tar.gz: ba7b5558199ebb2b11a16890c62e4e4b916d9ab9
3
+ metadata.gz: d450addd353c421e2096a7236b9df93588d33dd0
4
+ data.tar.gz: 1eed93cace8518f20b98d0576a672c2e32f825aa
5
5
  SHA512:
6
- metadata.gz: 05b899eb55fb736798eb495edce085e5c4eabaa92d5778c2fc7fd81959ff55f5b64003daa13a8751b543d119dd536bc2f81e5d225f93ed34bc3824082001ef38
7
- data.tar.gz: fbd8908440fdaff653e46cebe6c29480b353568ffc24bdcd4372b18ce1cec18a6f6b996db48e1d2ac39c9e5310236442e86487f13fe9abc9b98f7e73d884402e
6
+ metadata.gz: 787f6a8105570622d8846676e87f04bdeb53a15d88ffe6e18ba54afa264b7aeb4c893cfdafd1cf924c3ebdbfda6480aab88b32580bb334283cfec801cad12d17
7
+ data.tar.gz: abd365799a52bc3192712595b7574b8aad97975a66535bc78f073442e32c43c73b4ff8bfb167e71410ad0a567cc775914acc9f9ac1dbf8f979a6734eeb95ccde
data/Gemfile CHANGED
@@ -8,7 +8,7 @@ group :test do
8
8
  gem "guard-bundler", "~> 2.0", require: false
9
9
  gem "pry-nav"
10
10
  gem "rake"
11
- gem "rspec", "~> 3.3"
11
+ gem "rspec", "~> 2.99"
12
12
  gem "redis-namespace", "~> 1.4", "< 1.5"
13
13
  gem "codeclimate-test-reporter", require: false
14
14
  end
data/README.md CHANGED
@@ -58,29 +58,6 @@ All declared requests can be listed via `Cistern::Service#requests`.
58
58
  Foo::Client.requests # => [:get_bar, :get_bars]
59
59
  ```
60
60
 
61
- ##### Forward Compatible
62
-
63
- Ish.
64
-
65
- ```ruby
66
- # client/requests/get_bar.rb
67
- class Foo:Client::GetBar
68
-
69
- service Foo::Client
70
-
71
- def real(bar_id)
72
- connection.request("http://example.org/bar/#{bar_id}")
73
- end
74
-
75
- def mock
76
- # do some mock things
77
- end
78
- end
79
- ```
80
-
81
- In this context, `connection` is reference to the `Cistern::Service`.
82
-
83
-
84
61
  #### Models and Collections
85
62
 
86
63
  Models and collections have declaration semantics similar to requests. Models and collections are enumerated via `model` and `collection` respectively.
@@ -231,7 +208,7 @@ Patient::Mock.store_in(:hash)
231
208
 
232
209
  ### Model
233
210
 
234
- * `connection` represents the associated `Foo::Client` instance.
211
+ * `service` represents the associated `Foo::Client` instance.
235
212
  * `collection` represents the related collection (if applicable)
236
213
 
237
214
  Example
@@ -248,7 +225,7 @@ class Foo::Client::Bar < Cistern::Model
248
225
  params = {
249
226
  "id" => self.identity
250
227
  }
251
- self.connection.destroy_bar(params).body["request"]
228
+ self.service.destroy_bar(params).body["request"]
252
229
  end
253
230
 
254
231
  def save
@@ -262,11 +239,11 @@ class Foo::Client::Bar < Cistern::Model
262
239
  }
263
240
 
264
241
  if new_record?
265
- merge_attributes(connection.create_bar(params).body["bar"])
242
+ merge_attributes(service.create_bar(params).body["bar"])
266
243
  else
267
244
  requires :identity
268
245
 
269
- merge_attributes(connection.update_bar(params).body["bar"])
246
+ merge_attributes(service.update_bar(params).body["bar"])
270
247
  end
271
248
  end
272
249
  end
@@ -309,7 +286,7 @@ class Foo::Client::Bars < Cistern::Collection
309
286
  model Foo::Client::Bar
310
287
 
311
288
  def all(params = {})
312
- response = connection.get_bars(params)
289
+ response = service.get_bars(params)
313
290
 
314
291
  data = response.body
315
292
 
@@ -323,11 +300,11 @@ class Foo::Client::Bars < Cistern::Collection
323
300
  }
324
301
  params.merge!("location" => options[:location]) if options.key?(:location)
325
302
 
326
- connection.requests.new(connection.discover_bar(params).body["request"])
303
+ service.requests.new(service.discover_bar(params).body["request"])
327
304
  end
328
305
 
329
306
  def get(id)
330
- if data = connection.get_bar("id" => id).body["bar"]
307
+ if data = service.get_bar("id" => id).body["bar"]
331
308
  new(data)
332
309
  else
333
310
  nil
@@ -9,6 +9,7 @@ module Cistern
9
9
  Timeout = Class.new(Error)
10
10
 
11
11
  require 'cistern/hash'
12
+ require 'cistern/string'
12
13
  require 'cistern/mock'
13
14
  require 'cistern/wait_for'
14
15
  require 'cistern/attributes'
@@ -16,11 +17,10 @@ module Cistern
16
17
  require 'cistern/model'
17
18
  require 'cistern/service'
18
19
  require 'cistern/singular'
20
+ require 'cistern/request'
19
21
  require 'cistern/data'
20
22
  require 'cistern/data/hash'
21
23
  require 'cistern/data/redis'
22
- require 'cistern/request'
23
- require 'cistern/string'
24
24
 
25
25
  extend WaitFor
26
26
 
@@ -121,19 +121,9 @@ module Cistern::Attributes
121
121
  def read_attribute(name)
122
122
  options = self.class.attributes[name] || {}
123
123
  # record the attribute was accessed
124
- begin
125
- self.class.attributes[name.to_s.to_sym][:coverage_hits] += 1
126
- rescue
127
- nil
128
- end
129
-
130
- default = options[:default]
131
-
132
- unless default.nil?
133
- default = Marshal.load(Marshal.dump(default))
134
- end
124
+ self.class.attributes[name.to_s.to_sym][:coverage_hits] += 1 rescue nil
135
125
 
136
- attributes.fetch(name.to_s.to_sym, default)
126
+ attributes.fetch(name.to_s.to_sym, options[:default])
137
127
  end
138
128
 
139
129
  def write_attribute(name, value)
@@ -183,39 +173,26 @@ module Cistern::Attributes
183
173
  end
184
174
 
185
175
  def merge_attributes(new_attributes = {})
186
- protected_methods = (Cistern::Model.instance_methods - [:connection, :identity, :collection])
187
- ignored_attributes = self.class.ignored_attributes
188
- class_attributes = self.class.attributes
189
- class_aliases = self.class.aliases
190
-
191
176
  new_attributes.each do |_key, value|
192
- string_key = _key.kind_of?(String) ? _key : _key.to_s
193
- symbol_key = case _key
194
- when String
195
- _key.to_sym
196
- when Symbol
197
- _key
198
- else
199
- string_key.to_sym
200
- end
201
-
177
+ key = _key.to_s.to_sym
202
178
  # find nested paths
203
- value.is_a?(::Hash) && class_attributes.each do |name, options|
204
- if options[:squash] && options[:squash].first == string_key
205
- send("#{name}=", {symbol_key => value})
179
+ value.is_a?(::Hash) && self.class.attributes.each do |name, options|
180
+ if (options[:squash] || []).first == key.to_s
181
+ send("#{name}=", {key => value})
206
182
  end
207
183
  end
208
184
 
209
- unless ignored_attributes.include?(symbol_key)
210
- if class_aliases.has_key?(symbol_key)
211
- class_aliases[symbol_key].each do |aliased_key|
185
+ unless self.class.ignored_attributes.include?(key)
186
+ if self.class.aliases.has_key?(key)
187
+ self.class.aliases[key].each do |aliased_key|
212
188
  send("#{aliased_key}=", value)
213
189
  end
214
190
  end
215
191
 
216
- assignment_method = "#{string_key}="
217
- if !protected_methods.include?(symbol_key) && self.respond_to?(assignment_method, true)
218
- send(assignment_method, value)
192
+ protected_methods = Cistern::Model.instance_methods - [:service, :identity, :collection]
193
+
194
+ if !protected_methods.include?(key) && self.respond_to?("#{key}=", true)
195
+ send("#{key}=", value)
219
196
  end
220
197
  end
221
198
  end
@@ -259,7 +236,7 @@ module Cistern::Attributes
259
236
  protected
260
237
 
261
238
  def missing_attributes(args)
262
- ([:connection] | args).select{|arg| send("#{arg}").nil?}
239
+ ([:service] | args).select{|arg| send("#{arg}").nil?}
263
240
  end
264
241
 
265
242
  def changed!(attribute, from, to)
@@ -1,6 +1,4 @@
1
- class Cistern::Collection
2
- extend Cistern::Attributes::ClassMethods
3
- include Cistern::Attributes::InstanceMethods
1
+ module Cistern::Collection
4
2
 
5
3
  BLACKLISTED_ARRAY_METHODS = [
6
4
  :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
@@ -8,15 +6,21 @@ class Cistern::Collection
8
6
  :keep_if, :pop, :shift, :delete_at, :compact
9
7
  ].to_set # :nodoc:
10
8
 
11
- attr_accessor :records, :loaded, :connection
9
+ def self.service_collection(service, klass)
10
+ plural_name = Cistern::String.underscore(Cistern::String.demodulize(klass.name))
12
11
 
13
- alias service connection
12
+ service.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
13
+ def #{plural_name}(attributes={})
14
+ #{klass.name}.new(attributes.merge(service: self))
15
+ end
16
+ EOS
17
+ end
14
18
 
15
- def self.model(new_model=nil)
16
- if new_model == nil
17
- @model
18
- else
19
- @model = new_model
19
+ attr_accessor :records, :loaded, :service
20
+
21
+ module ClassMethods
22
+ def model(new_model=nil)
23
+ @model ||= new_model
20
24
  end
21
25
  end
22
26
 
@@ -75,7 +79,7 @@ class Cistern::Collection
75
79
  model.new(
76
80
  {
77
81
  :collection => self,
78
- :connection => connection,
82
+ :service => service,
79
83
  }.merge(attributes)
80
84
  )
81
85
  end
@@ -7,10 +7,6 @@ module Cistern::Formatter
7
7
  Cistern::Formatter::AwesomePrint
8
8
  elsif defined?(::Formatador)
9
9
  Cistern::Formatter::Formatador
10
- else
11
- Cistern::Formatter::Default
12
10
  end
13
11
  end
14
12
  end
15
-
16
- require 'cistern/formatter/default'
@@ -1,13 +1,19 @@
1
- class Cistern::Model
2
- extend Cistern::Attributes::ClassMethods
1
+ module Cistern::Model
3
2
  include Cistern::Attributes::InstanceMethods
4
3
 
5
- attr_accessor :collection, :connection
4
+ def self.included(klass)
5
+ klass.send(:extend, Cistern::Attributes::ClassMethods)
6
+ klass.send(:include, Cistern::Attributes::InstanceMethods)
7
+ end
6
8
 
7
- alias service connection
9
+ attr_accessor :collection, :service
8
10
 
9
11
  def inspect
10
- Cistern.formatter.call(self)
12
+ if Cistern.formatter
13
+ Cistern.formatter.call(self)
14
+ else
15
+ "#<#{self.class} #{self.identity}"
16
+ end
11
17
  end
12
18
 
13
19
  def initialize(attributes={})
@@ -50,15 +56,15 @@ class Cistern::Model
50
56
  end
51
57
  end
52
58
 
53
- def service
54
- self.connection ? self.connection.class : Cistern
59
+ def wait_for(timeout = self.service_class.timeout, interval = self.service_class.poll_interval, &block)
60
+ service_class.wait_for(timeout, interval) { reload && block.call(self) }
55
61
  end
56
62
 
57
- def wait_for(timeout = self.service.timeout, interval = self.service.poll_interval, &block)
58
- service.wait_for(timeout, interval) { reload && block.call(self) }
63
+ def wait_for!(timeout = self.service_class.timeout, interval = self.service_class.poll_interval, &block)
64
+ service_class.wait_for!(timeout, interval) { reload && block.call(self) }
59
65
  end
60
66
 
61
- def wait_for!(timeout = self.service.timeout, interval = self.service.poll_interval, &block)
62
- service.wait_for!(timeout, interval) { reload && block.call(self) }
67
+ def service_class
68
+ self.service ? self.service.class : Cistern
63
69
  end
64
70
  end
@@ -1,41 +1,28 @@
1
- class Cistern::Request
2
- def self.register(service, klass, method)
3
- service.requests << [method, {class: klass, method: method, new: true}]
4
- end
1
+ module Cistern::Request
2
+ def self.service_request(service, klass)
3
+ request = klass.request_name || Cistern::String.camelize(klass.name)
5
4
 
6
- def self.service(klass, options={})
7
- @service = klass
8
- @service_method = options[:method] || Cistern::String.underscore(
9
- Cistern::String.demodulize(self.name)
10
- )
11
- Cistern::Request.register(klass, self, @service_method)
12
- end
5
+ service::Mock.module_eval <<-EOS, __FILE__, __LINE__
6
+ def #{request}(*args)
7
+ #{klass}.new(self).mock(*args)
8
+ end
9
+ EOS
13
10
 
14
- def self.service_method
15
- @service_method
11
+ service::Real.module_eval <<-EOS, __FILE__, __LINE__
12
+ def #{request}(*args)
13
+ #{klass}.new(self).real(*args)
14
+ end
15
+ EOS
16
16
  end
17
17
 
18
- attr_reader :connection
19
-
20
- alias service connection
21
-
22
- def initialize(connection)
23
- @connection = connection
24
- end
25
-
26
- def _real(*args, &block)
27
- real(*args, &block)
28
- end
29
-
30
- def _mock(*args, &block)
31
- mock(*args, &block)
32
- end
18
+ attr_reader :service
33
19
 
34
- def real(*args, &block)
35
- raise NotImplementedError
20
+ def initialize(service)
21
+ @service = service
36
22
  end
37
23
 
38
- def mock(*args, &block)
39
- Cistern::Mock.not_implemented(self.class.service_method)
24
+ module ClassMethods
25
+ def request_name
26
+ end
40
27
  end
41
28
  end
@@ -42,6 +42,44 @@ class Cistern::Service
42
42
  def initialize(options={})
43
43
  end
44
44
  end
45
+
46
+ class Model
47
+ include Cistern::Model
48
+
49
+ def self.service
50
+ #{klass.name}
51
+ end
52
+ end
53
+
54
+ class Collection
55
+ include Cistern::Collection
56
+
57
+ def self.inherited(klass)
58
+ klass.extend(Cistern::Attributes::ClassMethods)
59
+ klass.extend(Cistern::Collection::ClassMethods)
60
+ klass.include(Cistern::Attributes::InstanceMethods)
61
+
62
+ Cistern::Collection.service_collection(service, klass)
63
+ end
64
+
65
+ def self.service
66
+ #{klass.name}
67
+ end
68
+ end
69
+
70
+ class Request
71
+ include Cistern::Request
72
+
73
+ def self.inherited(klass)
74
+ klass.extend(Cistern::Request::ClassMethods)
75
+
76
+ Cistern::Request.service_request(service, klass)
77
+ end
78
+
79
+ def self.service
80
+ #{klass.name}
81
+ end
82
+ end
45
83
  EOS
46
84
 
47
85
  klass.send(:const_set, :Timeout, Class.new(Cistern::Error))
@@ -57,30 +95,6 @@ class Cistern::Service
57
95
  klass::Real.timeout_error = klass::Timeout
58
96
  end
59
97
 
60
- def collection_path(collection_path = nil)
61
- if collection_path
62
- @collection_path = collection_path
63
- else
64
- @collection_path
65
- end
66
- end
67
-
68
- def model_path(model_path = nil)
69
- if model_path
70
- @model_path = model_path
71
- else
72
- @model_path
73
- end
74
- end
75
-
76
- def request_path(request_path = nil)
77
- if request_path
78
- @request_path = request_path
79
- else
80
- @request_path
81
- end
82
- end
83
-
84
98
  def collections
85
99
  @collections ||= []
86
100
  end
@@ -109,22 +123,10 @@ class Cistern::Service
109
123
  self.recognized_arguments.concat(args)
110
124
  end
111
125
 
112
- def model(model_name, options={})
113
- models << [model_name, options]
114
- end
115
-
116
126
  def mocked_requests
117
127
  @mocked_requests ||= []
118
128
  end
119
129
 
120
- def request(request_name, options={})
121
- requests << [request_name, options]
122
- end
123
-
124
- def collection(collection_name, options={})
125
- collections << [collection_name, options]
126
- end
127
-
128
130
  def validate_options(options={})
129
131
  required_options = Cistern::Hash.slice(options, *required_arguments)
130
132
 
@@ -141,91 +143,8 @@ class Cistern::Service
141
143
  end
142
144
  end
143
145
 
144
- def setup_requirements
145
- @required ||= false
146
- unless @required
147
-
148
- # setup models
149
- models.each do |model, options|
150
- unless options[:require] == false
151
- require(options[:require] || File.join(@model_path, model.to_s))
152
- end
153
-
154
- class_name = options[:class] || model.to_s.split("_").map(&:capitalize).join
155
- singular_name = options[:model] || model.to_s.gsub("/", "_")
156
-
157
- self.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
158
- def #{singular_name}(attributes={})
159
- #{service}::#{class_name}.new({connection: self}.merge(attributes))
160
- end
161
- EOS
162
- end
163
-
164
- # setup requests
165
- requests.each do |request, options|
166
- unless (options[:require] == false) || options[:new] || service::Real.method_defined?(request.to_s)
167
- require(options[:require] || File.join(@request_path, request.to_s))
168
- end
169
-
170
- if options[:new]
171
- klass = options.fetch(:class)
172
- method = options.fetch(:method)
173
-
174
- unless klass.instance_methods.include?(:mock)
175
- klass.class_eval <<-EOS, __FILE__, __LINE__
176
- def #{method}(*args)
177
- Cistern::Mock.not_implemented(request)
178
- end
179
- EOS
180
- end
181
-
182
- service::Real.module_eval <<-EOS, __FILE__, __LINE__
183
- def #{method}(*args)
184
- #{klass}.new(self)._real(*args)
185
- end
186
- EOS
187
-
188
- service::Mock.module_eval <<-EOS, __FILE__, __LINE__
189
- def #{method}(*args)
190
- #{klass}.new(self)._mock(*args)
191
- end
192
- EOS
193
- elsif service::Mock.method_defined?(request)
194
- mocked_requests << request
195
- else
196
- service::Mock.module_eval <<-EOS, __FILE__, __LINE__
197
- def #{request}(*args)
198
- Cistern::Mock.not_implemented(request)
199
- end
200
- EOS
201
- end
202
- end
203
-
204
- # setup collections
205
- collections.each do |collection, options|
206
- unless false == options[:require]
207
- require(options[:require] || File.join(@collection_path || @model_path, collection.to_s))
208
- end
209
-
210
- class_name = collection.to_s.
211
- split("/").map(&:capitalize).join("::").split("_").
212
- map { |s| "#{s[0].upcase}#{s[1..-1]}" }.join
213
- plural_name = options[:collection] || collection.to_s.gsub("/", "_")
214
-
215
- self.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
216
- def #{plural_name}(attributes={})
217
- #{service}::#{class_name}.new({connection: self}.merge(attributes))
218
- end
219
- EOS
220
- end
221
-
222
- @required = true
223
- end
224
- end
225
-
226
146
  def new(options={})
227
147
  validate_options(options)
228
- setup_requirements
229
148
 
230
149
  self.const_get(self.mocking? ? :Mock : :Real).new(options)
231
150
  end
@@ -2,7 +2,7 @@ class Cistern::Singular
2
2
  extend Cistern::Attributes::ClassMethods
3
3
  include Cistern::Attributes::InstanceMethods
4
4
 
5
- attr_accessor :connection
5
+ attr_accessor :service
6
6
 
7
7
  def inspect
8
8
  if Cistern.formatter
@@ -1,5 +1,20 @@
1
1
  class Cistern::String
2
- # stolen from activesupport/lib/active_support/inflector/methods.rb, line 198
2
+ def self.camelize(string)
3
+ string.gsub(/[A-Z]+/) { |w| "_#{w.downcase}" }.gsub(/^_/, "")
4
+ end
5
+
6
+ # File activesupport/lib/active_support/inflector/methods.rb, line 90
7
+ def self.underscore(camel_cased_word)
8
+ word = camel_cased_word.to_s.gsub('::', '/')
9
+ #word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
10
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
11
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
12
+ word.tr!("-", "_")
13
+ word.downcase!
14
+ word
15
+ end
16
+
17
+ # File activesupport/lib/active_support/inflector/methods.rb, line 168
3
18
  def self.demodulize(path)
4
19
  path = path.to_s
5
20
  if i = path.rindex('::')
@@ -9,15 +24,8 @@ class Cistern::String
9
24
  end
10
25
  end
11
26
 
12
- # stolen from activesupport/lib/active_support/inflector/methods.rb, line 90
13
- def self.underscore(camel_cased_word)
14
- return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
15
- word = camel_cased_word.to_s.gsub(/::/, '/')
16
- #word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'}#{$2.downcase}" }
17
- word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
18
- word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
19
- word.tr!("-", "_")
20
- word.downcase!
21
- word
27
+ # @todo omg so bad
28
+ def self.pluralize(string)
29
+ "#{string}s"
22
30
  end
23
31
  end
@@ -1,3 +1,3 @@
1
1
  module Cistern
2
- VERSION = "0.12.3"
2
+ VERSION = "1.0.0.pre"
3
3
  end
@@ -1,13 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Cistern::Collection" do
4
-
5
- class SampleCollectionModel < Cistern::Model
4
+ class SampleCollectionModel < Sample::Model
6
5
  identity :id
7
6
  attribute :name
8
7
  end
9
8
 
10
- class SampleCollection < Cistern::Collection
9
+ class SampleCollection < Sample::Collection
11
10
  model SampleCollectionModel
12
11
 
13
12
  def all
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Cistern::Model#dirty" do
4
- class DirtySpec < Cistern::Model
4
+ class DirtySpec < Sample::Model
5
5
  identity :id
6
6
 
7
7
  attribute :name
@@ -1,75 +1,41 @@
1
1
  require 'spec_helper'
2
2
 
3
- class Inspector < Cistern::Model
4
- identity :id
5
- attribute :name
6
- end
7
-
8
- class Anon < Cistern::Model
9
- attribute :chan
10
- end
11
-
12
- class Inspectors < Cistern::Collection
13
- model Inspector
14
-
15
- def all(options={})
16
- merge_attributes(options)
17
- self.load([{id: 1, name: "2"},{id: 3, name: "4"}])
18
- end
19
- end
20
-
21
- describe Cistern::Formatter::Default do
22
- before { Cistern.formatter = described_class }
23
-
24
- it "formats a model" do
25
- expect(
26
- Inspector.new(id: 1, name: "name").inspect
27
- ).to match(
28
- /<Inspector:0x[a-z0-9]+> {:id=>1, :name=>\"name\"}/
29
- )
30
-
31
- Anon.inspect
32
- end
33
-
34
- it "formats a collection" do
35
- expect(
36
- Inspectors.new.all.inspect
37
- ).to match(
38
- /<Inspectors:0x[a-z0-9]+> {} records/
39
- )
3
+ describe "#inspect" do
4
+ class Inspector < Sample::Model
5
+ identity :id
6
+ attribute :name
40
7
  end
41
- end
42
8
 
43
- describe Cistern::Formatter::AwesomePrint do
44
- before { Cistern.formatter = described_class }
9
+ class Inspectors < Sample::Collection
10
+ model Inspector
45
11
 
46
- it "formats a model" do
47
- expect(
48
- Inspector.new(id: 1, name: "name").inspect
49
- ).to match(
50
- /(?x-mi:\#<Inspector:0x[0-9a-f]+>\ {\n\ \ \ \ \ \ :id\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[1;34m1\x1B\[0m,\n\ \ \ \ :name\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[0;33m"name"\x1B\[0m\n})/
51
- )
12
+ def all(options={})
13
+ merge_attributes(options)
14
+ self.load([{id: 1, name: "2"},{id: 3, name: "4"}])
15
+ end
52
16
  end
53
17
 
54
- it "formats a collection" do
55
- expect(Inspectors.new.all.inspect).to match(/Inspectors\s+{.*}$/m) # close enough
56
- end
57
- end
18
+ describe "Cistern::Model" do
19
+ it "should use awesome_print" do
20
+ Cistern.formatter = Cistern::Formatter::AwesomePrint
58
21
 
59
- describe Cistern::Formatter::Formatador do
60
- before { Cistern.formatter = described_class }
22
+ Inspector.new(id: 1, name: "name").inspect.match /(?x-mi:\#<Inspector:0x[0-9a-f]+>\ {\n\ \ \ \ \ \ :id\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[1;34m1\x1B\[0m,\n\ \ \ \ :name\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[0;33m"name"\x1B\[0m\n})/
23
+ end
61
24
 
62
- it "formats a model" do
63
- Cistern.formatter = Cistern::Formatter::Formatador
25
+ it "should use formatador" do
26
+ Cistern.formatter = Cistern::Formatter::Formatador
64
27
 
65
- expect(Inspector.new(id: 1, name: "name").inspect).to eq(%q{ <Inspector
28
+ expect(Inspector.new(id: 1, name: "name").inspect).to eq(%q{ <Inspector
66
29
  id=1,
67
30
  name="name"
68
31
  >})
32
+ end
69
33
  end
70
34
 
71
- it "formats a collection" do
72
- expect(Inspectors.new.all.inspect).to eq(%q{ <Inspectors
35
+ describe "Cistern::Collection" do
36
+ it "should use formatador" do
37
+ Cistern.formatter = Cistern::Formatter::Formatador
38
+ expect(Inspectors.new.all.inspect).to eq(%q{ <Inspectors
73
39
  [
74
40
  <Inspector
75
41
  id=1,
@@ -81,5 +47,11 @@ describe Cistern::Formatter::Formatador do
81
47
  >
82
48
  ]
83
49
  >})
50
+ end
51
+
52
+ it "should use awesome_print" do
53
+ Cistern.formatter = Cistern::Formatter::AwesomePrint
54
+ expect(Inspectors.new.all.inspect).to match(/Inspectors\s+{.*}$/m) # close enough
55
+ end
84
56
  end
85
57
  end
@@ -1,37 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'mock data' do
4
- class Patient < Cistern::Service
5
- request :diagnosis
6
- request :treat
7
-
8
- class Real
9
- def diagnosis(options={})
10
- end
4
+ class Diagnosis < Sample::Request
5
+ def real(diagnosis)
6
+ end
11
7
 
12
- def treat(options={})
13
- end
8
+ def mock(diagnosis)
9
+ service.data.store(:diagnosis, service.data.fetch(:diagnosis) + [diagnosis])
14
10
  end
11
+ end
15
12
 
16
- class Mock
17
- def diagnosis(diagnosis)
18
- #self.data[:diagnosis] << rand(2) == 0 ? "sick" : "healthy"
19
- self.data.store(:diagnosis, self.data.fetch(:diagnosis) + [diagnosis])
20
- end
13
+ class Treat < Sample::Request
14
+ def real(treatment)
15
+ end
21
16
 
22
- def treat(treatment)
23
- self.data[:treatments] += [treatment]
24
- end
17
+ def mock(treatment)
18
+ service.data[:treatments] += [treatment]
25
19
  end
26
20
  end
27
21
 
28
22
  shared_examples "mock_data#backend" do |backend, options|
29
23
  it "should store mock data" do
30
- Patient.mock!
31
- Patient::Mock.store_in(backend, options)
32
- Patient.reset!
24
+ Sample.mock!
25
+ Sample::Mock.store_in(backend, options)
26
+ Sample.reset!
33
27
 
34
- p = Patient.new
28
+ p = Sample.new
35
29
  p.diagnosis("sick")
36
30
  expect(p.data[:diagnosis]).to eq(["sick"])
37
31
 
@@ -42,7 +36,7 @@ describe 'mock data' do
42
36
  p.treat("healthy")
43
37
  expect(p.data[:treatments]).to eq(["healthy"])
44
38
 
45
- Patient.reset!
39
+ Sample.reset!
46
40
 
47
41
  expect(p.data[:treatments]).to eq([])
48
42
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "Cistern::Model" do
4
4
  describe "#update" do
5
- class UpdateSpec < Cistern::Model
5
+ class UpdateSpec < Sample::Model
6
6
  identity :id
7
7
  attribute :name
8
8
  attribute :properties
@@ -21,7 +21,7 @@ describe "Cistern::Model" do
21
21
  end
22
22
 
23
23
  it "should duplicate a model" do
24
- class DupSpec < Cistern::Model
24
+ class DupSpec < Sample::Model
25
25
  identity :id
26
26
  attribute :name
27
27
  attribute :properties
@@ -38,7 +38,7 @@ describe "Cistern::Model" do
38
38
  end
39
39
 
40
40
  context "attribute parsing" do
41
- class TypeSpec < Cistern::Model
41
+ class TypeSpec < Sample::Model
42
42
  identity :id
43
43
  attribute :name, type: :string
44
44
  attribute :created_at, type: :time
@@ -155,17 +155,17 @@ describe "Cistern::Model" do
155
155
 
156
156
  describe "#requires" do
157
157
  it "should raise if attribute not provided" do
158
- expect { TypeSpec.new({"connection" => "fake", "something" => {"id" => "12"}}).save }.to raise_exception(ArgumentError)
158
+ expect { TypeSpec.new({"service" => "fake", "something" => {"id" => "12"}}).save }.to raise_exception(ArgumentError)
159
159
  end
160
160
 
161
161
  it "should raise if attribute is provided and is nil" do
162
- expect { TypeSpec.new({"connection" => "fake", "custom" => nil}).save }.to raise_exception(ArgumentError)
162
+ expect { TypeSpec.new({"service" => "fake", "custom" => nil}).save }.to raise_exception(ArgumentError)
163
163
  end
164
164
  end
165
165
  end
166
166
 
167
167
  context "attribute coverage info collecting", :coverage do
168
- class CoverageSpec < Cistern::Model
168
+ class CoverageSpec < Sample::Model
169
169
  identity :id
170
170
 
171
171
  attribute :used, type: :string
@@ -1,29 +1,37 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Cistern do
3
+ describe "Cistern::Request" do
4
4
  class SampleService < Cistern::Service
5
+ recognizes :key
6
+
5
7
  class Real
8
+ attr_reader :service_args
9
+
10
+ def initialize(*args)
11
+ @service_args = args
12
+ end
6
13
  end
7
14
  end
8
15
 
9
- class SampleService::GetSample < Cistern::Request
10
- service SampleService
11
-
16
+ # @todo Sample::Service.request
17
+ class ListSamples < SampleService::Request
18
+ # @todo name
19
+ # name :list_all_samples
12
20
  def real(*args)
13
- args
21
+ service.service_args + args + ["real"]
14
22
  end
15
- end
16
23
 
17
- class ShowSamples < Cistern::Request
18
- service SampleService, method: :list_samples
19
-
20
- def real(*args)
21
- {"samples" => args}
24
+ def mock(*args)
25
+ args + ["mock"]
22
26
  end
23
27
  end
24
28
 
25
- it "allows requests to be created in a forward compatible structure" do
26
- expect(SampleService.new.get_sample("likewhoa")).to contain_exactly("likewhoa")
27
- expect(SampleService.new.list_samples("likewhoa")).to eq("samples" => ["likewhoa"])
29
+ it "should execute a new-style request" do
30
+ expect(SampleService.new.list_samples("sample1")).to eq([{}, "sample1", "real"])
31
+ expect(SampleService::Real.new.list_samples("sample2")).to eq(["sample2", "real"])
32
+ expect(SampleService::Mock.new.list_samples("sample3")).to eq(["sample3", "mock"])
33
+
34
+ # service access
35
+ expect(SampleService.new(:key => "value").list_samples("stat")).to eq([{:key => "value"}, "stat", "real"])
28
36
  end
29
37
  end
File without changes
@@ -6,8 +6,8 @@ describe "Cistern::Singular" do
6
6
  attribute :count, type: :number
7
7
 
8
8
  def fetch_attributes
9
- #test that initialize waits for connection to be defined
10
- raise "missing connection" unless connection
9
+ #test that initialize waits for service to be defined
10
+ raise "missing service" unless service
11
11
 
12
12
  @counter ||= 0
13
13
  @counter += 1
@@ -16,11 +16,11 @@ describe "Cistern::Singular" do
16
16
  end
17
17
 
18
18
  it "should work" do
19
- expect(SampleSingular.new(connection: :fake).name).to eq("amazing")
19
+ expect(SampleSingular.new(service: :fake).name).to eq("amazing")
20
20
  end
21
21
 
22
22
  it "should reload" do
23
- singular = SampleSingular.new(connection: :fake)
23
+ singular = SampleSingular.new(service: :fake)
24
24
  old_count = singular.count
25
25
  expect(singular.count).to eq(old_count)
26
26
  expect(singular.reload.count).to be > old_count
@@ -4,10 +4,13 @@ if ENV["TRAVIS"]
4
4
  end
5
5
 
6
6
  require File.expand_path('../../lib/cistern', __FILE__)
7
+ Dir[File.expand_path("../{support,shared,matchers,fixtures}/*.rb", __FILE__)].each{|f| require(f)}
7
8
 
8
9
  Bundler.require(:test)
9
10
 
10
11
  RSpec.configure do |c|
12
+ c.treat_symbols_as_metadata_keys_with_true_values = true
13
+
11
14
  if Kernel.respond_to?(:caller_locations)
12
15
  require File.expand_path('../../lib/cistern/coverage', __FILE__)
13
16
  else
@@ -0,0 +1 @@
1
+ class Sample < Cistern::Service; end
@@ -1,23 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
- class WaitForService < Cistern::Service
4
- model :wait_for_model, require: false
5
- collection :wait_for_models, require: false
6
-
7
- class Real
8
- def initialize(*args)
9
- end
10
- end
11
- end
12
-
13
- class WaitForService::WaitForModel < Cistern::Model
3
+ class WaitForModel < Sample::Model
14
4
  identity :id
15
5
 
16
6
  attribute :name
17
7
  end
18
8
 
19
- class WaitForService::WaitForModels < Cistern::Collection
20
- model WaitForService::WaitForModel
9
+ class WaitForModels < Sample::Collection
10
+ model WaitForModel
21
11
 
22
12
  def get(identity)
23
13
  self
@@ -37,17 +27,17 @@ describe 'Cistern#wait_for!' do
37
27
  end
38
28
 
39
29
  describe 'Cistern::Model#wait_for!' do
40
- let(:service) { WaitForService.new }
30
+ let(:service) { Sample.new }
41
31
  let(:model) { service.wait_for_models.new(identity: 1) }
42
32
 
43
33
  it "should raise if timeout exceeded" do
44
- expect { model.wait_for!(0, 0) { false } }.to raise_exception(WaitForService::Timeout)
34
+ expect { model.wait_for!(0, 0) { false } }.to raise_exception(Sample::Timeout)
45
35
  end
46
36
  end
47
37
 
48
38
 
49
39
  describe "WaitForModel#timeout" do
50
- let(:service) { WaitForService.new }
40
+ let(:service) { Sample.new }
51
41
  let(:model) { service.wait_for_models.new(identity: 1) }
52
42
 
53
43
  it "should use service-specific timeout in #wait_for" do
@@ -59,7 +49,7 @@ describe "WaitForModel#timeout" do
59
49
  timeout(2) do
60
50
  expect do
61
51
  model.wait_for! { sleep(0.2); elapsed += 0.2; elapsed > 0.2 }
62
- end.to raise_exception(WaitForService::Timeout)
52
+ end.to raise_exception(Sample::Timeout)
63
53
  end
64
54
  end
65
55
 
@@ -72,7 +62,7 @@ describe "WaitForModel#timeout" do
72
62
  timeout(2) do
73
63
  expect do
74
64
  model.wait_for!(0.1) { sleep(0.2); elapsed += 0.2; elapsed > 0.2 }
75
- end.to raise_exception(WaitForService::Timeout)
65
+ end.to raise_exception(Sample::Timeout)
76
66
  end
77
67
  end
78
68
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cistern
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 1.0.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Lane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-30 00:00:00.000000000 Z
11
+ date: 2014-10-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: API client framework extracted from Fog
14
14
  email:
@@ -17,7 +17,6 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - ".gemrelease"
21
20
  - ".gitignore"
22
21
  - ".travis.yml"
23
22
  - Gemfile
@@ -36,7 +35,6 @@ files:
36
35
  - lib/cistern/data/redis.rb
37
36
  - lib/cistern/formatter.rb
38
37
  - lib/cistern/formatter/awesome_print.rb
39
- - lib/cistern/formatter/default.rb
40
38
  - lib/cistern/formatter/formatador.rb
41
39
  - lib/cistern/hash.rb
42
40
  - lib/cistern/mock.rb
@@ -55,8 +53,10 @@ files:
55
53
  - spec/mock_data_spec.rb
56
54
  - spec/model_spec.rb
57
55
  - spec/request_spec.rb
56
+ - spec/service_spec.rb
58
57
  - spec/singular_spec.rb
59
58
  - spec/spec_helper.rb
59
+ - spec/support/service.rb
60
60
  - spec/wait_for_spec.rb
61
61
  homepage: http://joshualane.com/cistern
62
62
  licenses:
@@ -73,12 +73,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
73
  version: '0'
74
74
  required_rubygems_version: !ruby/object:Gem::Requirement
75
75
  requirements:
76
- - - ">="
76
+ - - ">"
77
77
  - !ruby/object:Gem::Version
78
- version: '0'
78
+ version: 1.3.1
79
79
  requirements: []
80
80
  rubyforge_project:
81
- rubygems_version: 2.6.12
81
+ rubygems_version: 2.2.2
82
82
  signing_key:
83
83
  specification_version: 4
84
84
  summary: API client framework
@@ -90,6 +90,9 @@ test_files:
90
90
  - spec/mock_data_spec.rb
91
91
  - spec/model_spec.rb
92
92
  - spec/request_spec.rb
93
+ - spec/service_spec.rb
93
94
  - spec/singular_spec.rb
94
95
  - spec/spec_helper.rb
96
+ - spec/support/service.rb
95
97
  - spec/wait_for_spec.rb
98
+ has_rdoc:
@@ -1,3 +0,0 @@
1
- ---
2
- bump:
3
- tag: true
@@ -1,22 +0,0 @@
1
- module Cistern::Formatter::Default
2
- class << self
3
- def call(object)
4
- case object
5
- when Cistern::Collection
6
- format_collection(object)
7
- when Cistern::Model
8
- format_model(object)
9
- else
10
- object.to_s
11
- end
12
- end
13
-
14
- def format_model(model)
15
- "#{model.to_s} #{model.attributes.inspect}"
16
- end
17
-
18
- def format_collection(collection)
19
- "#{collection.to_s} #{collection.attributes.inspect} records=[#{collection.records.map { |m| format_model(m) }.join(", ")}]"
20
- end
21
- end
22
- end