cistern 0.11.3 → 0.12.1

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: 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: