cistern 0.11.3 → 0.12.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a7f9a02401d9c9e5c38402adb3ed56d8abbf143
4
- data.tar.gz: 3244f949b14837163187b45dae902531f60af58a
3
+ metadata.gz: 596a794e4f9c5986b6d3163405445f2712df6152
4
+ data.tar.gz: 7e49adeffc52e77885f8ab6dd4b409b0591d5bc4
5
5
  SHA512:
6
- metadata.gz: 4ae10e49af345b7879c1b2f5ec8a88edfc2e18cc773a81e9b30205cd957c39ef404a606f1cc0344e9251fce2a6656df1d4f972a715ba45f8885aca3e62e9e809
7
- data.tar.gz: 77df65c3624f3512296491173ab6bcd9b150f3b2bafff6169063b5e7f182ef607dbc0e56500d4d82cd324d68eaa65041b1e9643da28db3f338533fffe4fe840c
6
+ metadata.gz: 9046ac54d8b3c92b9665431dd56651e4f5985c1512bba516395ac3910ae14b1806ea1a1d1cb0fb762abd1f70c010863fdaae405c258486653f9719597786565e
7
+ data.tar.gz: a46cf7e5877fb598f0b37525f7feb451f0fa8a730a8ecaba605b924d6f1a3aa96e874d5e91bcb893a7941d8e142b2ec3082a9a17603388debb238574ff1f96b7
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", "~> 2.99"
11
+ gem "rspec", "~> 3.3"
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,6 +58,29 @@ 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
+
61
84
  #### Models and Collections
62
85
 
63
86
  Models and collections have declaration semantics similar to requests. Models and collections are enumerated via `model` and `collection` respectively.
@@ -0,0 +1,22 @@
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
@@ -7,6 +7,10 @@ module Cistern::Formatter
7
7
  Cistern::Formatter::AwesomePrint
8
8
  elsif defined?(::Formatador)
9
9
  Cistern::Formatter::Formatador
10
+ else
11
+ Cistern::Formatter::Default
10
12
  end
11
13
  end
12
14
  end
15
+
16
+ require 'cistern/formatter/default'
data/lib/cistern/model.rb CHANGED
@@ -5,11 +5,7 @@ class Cistern::Model
5
5
  attr_accessor :collection, :connection
6
6
 
7
7
  def inspect
8
- if Cistern.formatter
9
- Cistern.formatter.call(self)
10
- else
11
- "#<#{self.class} #{self.identity}"
12
- end
8
+ Cistern.formatter.call(self)
13
9
  end
14
10
 
15
11
  def initialize(attributes={})
@@ -0,0 +1,41 @@
1
+ class Cistern::Request
2
+ def self.register(service, klass, method)
3
+ service.requests << [method, {class: klass, method: method, new: true}]
4
+ end
5
+
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
13
+
14
+ def self.service_method
15
+ @service_method
16
+ end
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
33
+
34
+ def real(*args, &block)
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def mock(*args, &block)
39
+ Cistern::Mock.not_implemented(self.class.service_method)
40
+ end
41
+ end
@@ -163,11 +163,34 @@ class Cistern::Service
163
163
 
164
164
  # setup requests
165
165
  requests.each do |request, options|
166
- unless options[:require] == false || service::Real.method_defined?(request.to_s)
166
+ unless (options[:require] == false) || options[:new] || service::Real.method_defined?(request.to_s)
167
167
  require(options[:require] || File.join(@request_path, request.to_s))
168
168
  end
169
169
 
170
- if service::Mock.method_defined?(request)
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)
171
194
  mocked_requests << request
172
195
  else
173
196
  service::Mock.module_eval <<-EOS, __FILE__, __LINE__
@@ -180,11 +203,13 @@ class Cistern::Service
180
203
 
181
204
  # setup collections
182
205
  collections.each do |collection, options|
183
- unless options[:require] == false
206
+ unless false == options[:require]
184
207
  require(options[:require] || File.join(@collection_path || @model_path, collection.to_s))
185
208
  end
186
209
 
187
- class_name = collection.to_s.split("/").map(&:capitalize).join("::").split("_").map { |s| "#{s[0].upcase}#{s[1..-1]}" }.join
210
+ class_name = collection.to_s.
211
+ split("/").map(&:capitalize).join("::").split("_").
212
+ map { |s| "#{s[0].upcase}#{s[1..-1]}" }.join
188
213
  plural_name = options[:collection] || collection.to_s.gsub("/", "_")
189
214
 
190
215
  self.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
@@ -0,0 +1,23 @@
1
+ class Cistern::String
2
+ # stolen from activesupport/lib/active_support/inflector/methods.rb, line 198
3
+ def self.demodulize(path)
4
+ path = path.to_s
5
+ if i = path.rindex('::')
6
+ path[(i+2)..-1]
7
+ else
8
+ path
9
+ end
10
+ end
11
+
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
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Cistern
2
- VERSION = "0.11.3"
2
+ VERSION = "0.12.1"
3
3
  end
data/lib/cistern.rb CHANGED
@@ -19,6 +19,8 @@ module Cistern
19
19
  require 'cistern/data'
20
20
  require 'cistern/data/hash'
21
21
  require 'cistern/data/redis'
22
+ require 'cistern/request'
23
+ require 'cistern/string'
22
24
 
23
25
  extend WaitFor
24
26
 
@@ -1,42 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#inspect" do
4
- class Inspector < Cistern::Model
5
- identity :id
6
- attribute :name
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"}])
7
18
  end
19
+ end
8
20
 
9
- class Inspectors < Cistern::Collection
21
+ describe Cistern::Formatter::Default do
22
+ before { Cistern.formatter = described_class }
10
23
 
11
- model Inspector
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
+ )
12
30
 
13
- def all(options={})
14
- merge_attributes(options)
15
- self.load([{id: 1, name: "2"},{id: 3, name: "4"}])
16
- end
31
+ Anon.inspect
17
32
  end
18
33
 
19
- describe "Cistern::Model" do
20
- it "should use awesome_print" do
21
- Cistern.formatter = Cistern::Formatter::AwesomePrint
34
+ it "formats a collection" do
35
+ expect(
36
+ Inspectors.new.all.inspect
37
+ ).to match(
38
+ /<Inspectors:0x[a-z0-9]+> {} records/
39
+ )
40
+ end
41
+ end
22
42
 
23
- 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})/
24
- end
43
+ describe Cistern::Formatter::AwesomePrint do
44
+ before { Cistern.formatter = described_class }
25
45
 
26
- it "should use formatador" do
27
- Cistern.formatter = Cistern::Formatter::Formatador
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
+ )
52
+ end
53
+
54
+ it "formats a collection" do
55
+ expect(Inspectors.new.all.inspect).to match(/Inspectors\s+{.*}$/m) # close enough
56
+ end
57
+ end
28
58
 
29
- expect(Inspector.new(id: 1, name: "name").inspect).to eq(%q{ <Inspector
59
+ describe Cistern::Formatter::Formatador do
60
+ before { Cistern.formatter = described_class }
61
+
62
+ it "formats a model" do
63
+ Cistern.formatter = Cistern::Formatter::Formatador
64
+
65
+ expect(Inspector.new(id: 1, name: "name").inspect).to eq(%q{ <Inspector
30
66
  id=1,
31
67
  name="name"
32
68
  >})
33
- end
34
69
  end
35
70
 
36
- describe "Cistern::Collection" do
37
- it "should use formatador" do
38
- Cistern.formatter = Cistern::Formatter::Formatador
39
- expect(Inspectors.new.all.inspect).to eq(%q{ <Inspectors
71
+ it "formats a collection" do
72
+ expect(Inspectors.new.all.inspect).to eq(%q{ <Inspectors
40
73
  [
41
74
  <Inspector
42
75
  id=1,
@@ -48,11 +81,5 @@ describe "#inspect" do
48
81
  >
49
82
  ]
50
83
  >})
51
- end
52
-
53
- it "should use awesome_print" do
54
- Cistern.formatter = Cistern::Formatter::AwesomePrint
55
- expect(Inspectors.new.all.inspect).to match(/Inspectors\s+{.*}$/m) # close enough
56
- end
57
84
  end
58
85
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cistern do
4
+ class SampleService < Cistern::Service
5
+ class Real
6
+ end
7
+ end
8
+
9
+ class SampleService::GetSample < Cistern::Request
10
+ service SampleService
11
+
12
+ def real(*args)
13
+ args
14
+ end
15
+ end
16
+
17
+ class ShowSamples < Cistern::Request
18
+ service SampleService, method: :list_samples
19
+
20
+ def real(*args)
21
+ {"samples" => args}
22
+ end
23
+ end
24
+
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"])
28
+ end
29
+ end
data/spec/spec_helper.rb CHANGED
@@ -8,8 +8,6 @@ require File.expand_path('../../lib/cistern', __FILE__)
8
8
  Bundler.require(:test)
9
9
 
10
10
  RSpec.configure do |c|
11
- c.treat_symbols_as_metadata_keys_with_true_values = true
12
-
13
11
  if Kernel.respond_to?(:caller_locations)
14
12
  require File.expand_path('../../lib/cistern/coverage', __FILE__)
15
13
  else
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.11.3
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Lane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-31 00:00:00.000000000 Z
11
+ date: 2015-09-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: API client framework extracted from Fog
14
14
  email:
@@ -36,12 +36,15 @@ files:
36
36
  - lib/cistern/data/redis.rb
37
37
  - lib/cistern/formatter.rb
38
38
  - lib/cistern/formatter/awesome_print.rb
39
+ - lib/cistern/formatter/default.rb
39
40
  - lib/cistern/formatter/formatador.rb
40
41
  - lib/cistern/hash.rb
41
42
  - lib/cistern/mock.rb
42
43
  - lib/cistern/model.rb
44
+ - lib/cistern/request.rb
43
45
  - lib/cistern/service.rb
44
46
  - lib/cistern/singular.rb
47
+ - lib/cistern/string.rb
45
48
  - lib/cistern/timeout.rb
46
49
  - lib/cistern/version.rb
47
50
  - lib/cistern/wait_for.rb
@@ -51,6 +54,7 @@ files:
51
54
  - spec/hash_spec.rb
52
55
  - spec/mock_data_spec.rb
53
56
  - spec/model_spec.rb
57
+ - spec/request_spec.rb
54
58
  - spec/singular_spec.rb
55
59
  - spec/spec_helper.rb
56
60
  - spec/wait_for_spec.rb
@@ -74,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
78
  version: '0'
75
79
  requirements: []
76
80
  rubyforge_project:
77
- rubygems_version: 2.2.2
81
+ rubygems_version: 2.4.5
78
82
  signing_key:
79
83
  specification_version: 4
80
84
  summary: API client framework
@@ -85,7 +89,7 @@ test_files:
85
89
  - spec/hash_spec.rb
86
90
  - spec/mock_data_spec.rb
87
91
  - spec/model_spec.rb
92
+ - spec/request_spec.rb
88
93
  - spec/singular_spec.rb
89
94
  - spec/spec_helper.rb
90
95
  - spec/wait_for_spec.rb
91
- has_rdoc: