saddle 0.0.43 → 0.0.44

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.
data/.gitignore CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  # Gems
9
9
  *.gem
10
+ Gemfile.lock
10
11
 
11
12
  # IDEs
12
13
  .idea
@@ -1,3 +1,14 @@
1
+ # 0.0.44
2
+ * Fixed a bug where child endpoints were being attached to the parent's class. This would
3
+ cause problems because the root node's class is always TraversalEndpoint, and would be shared
4
+ amongst concrete clients.
5
+
6
+ # 0.0.43
7
+ * Fixed a bug where non-string path elements were crashing
8
+
9
+ # 0.0.42
10
+ * Fixed a bug where nil actions resulted in a trailing /
11
+
1
12
  # 0.0.41
2
13
  * Cleanup of the path building chain makes nicer URLs
3
14
 
data/Gemfile CHANGED
@@ -1,10 +1,7 @@
1
1
  source 'https://rubygems.org'
2
+ gemspec
2
3
 
3
4
 
4
- gem 'activesupport', '>= 3.0', :require => 'active_support'
5
- gem 'faraday', '~> 0.8.7'
6
- gem 'faraday_middleware', '~> 0.9.0'
7
-
8
5
  group :test do
9
6
  gem 'rake'
10
7
  gem 'rspec', '~> 2.14.1'
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'erb'
4
+ require 'ostruct'
5
+
6
+ require 'active_support/core_ext/string'
7
+
8
+
9
+ # Creation options
10
+ # TODO: read via CLI
11
+ settings = {
12
+ service_name: 'Example',
13
+ author_name: 'Mike Lewis',
14
+ author_email: 'mike.lewis@airbnb.com',
15
+ github_account: 'airbnb',
16
+ }
17
+
18
+
19
+ # This holds the project settings and realizes templates
20
+ class ProjectGenerator
21
+ attr_reader :settings
22
+
23
+ # Expected settings:
24
+ # service_name
25
+ # author_name
26
+ # author_email
27
+ # github_account
28
+ def initialize(settings)
29
+ settings[:project_name] = "#{settings[:service_name].underscore}-client"
30
+ settings[:root_module] = settings[:service_name].split('_').map(&:capitalize).join('')
31
+ settings[:saddle_version] = Saddle::VERSION
32
+ @settings = OpenStruct.new(settings)
33
+
34
+ @template_dir = File.join(File.dirname(__FILE__), 'template')
35
+ @output_dir = '.'
36
+ end
37
+
38
+ # Transform a template file into the output directory
39
+ def transform_template(in_file, out_file=nil)
40
+ out_file = in_file if out_file.nil?
41
+ puts "Processing: #{out_file}"
42
+
43
+ # Ensure the directory is there
44
+ FileUtils.mkdir_p(File.dirname(out_file))
45
+ # Write the processed template
46
+ #puts File.read(File.join(@template_dir, in_file), 'r')
47
+ File.open(File.join(@output_dir, out_file), 'w') do |output|
48
+ output.puts(
49
+ ERB.new(
50
+ File.read(File.join(@template_dir, in_file))
51
+ ).result(
52
+ @settings.instance_eval { binding }
53
+ )
54
+ )
55
+ end
56
+ end
57
+ end
58
+
59
+ pg = ProjectGenerator.new(settings)
60
+ # /lib
61
+ # Create the contents of the gem directory in the correctly named directory
62
+ %w(
63
+ endpoints/status.rb
64
+ middleware/exception_raiser.rb
65
+ exceptions.rb
66
+ stub.rb
67
+ version.rb
68
+ ).each do |tmpl|
69
+ pg.transform_template("lib/saddle-client/#{tmpl}", "lib/#{pg.settings.project_name}/#{tmpl}")
70
+ end
71
+ pg.transform_template('lib/saddle-client.rb', "lib/#{pg.settings.project_name}.rb")
72
+ # /spec
73
+ pg.transform_template('spec/integration/status_spec.rb')
74
+ pg.transform_template('spec/middleware/exception_raiser_spec.rb')
75
+ pg.transform_template('spec/stub/stub_spec.rb')
76
+ pg.transform_template('spec/spec_helper.rb')
77
+ # /
78
+ pg.transform_template('.gitignore')
79
+ pg.transform_template('.rspec')
80
+ pg.transform_template('Gemfile')
81
+ pg.transform_template('LICENSE')
82
+ pg.transform_template('README.md')
83
+ pg.transform_template('saddle-client.gemspec', "#{pg.settings.project_name}.gemspec")
@@ -0,0 +1,20 @@
1
+ # Ignore temporary files
2
+ *.sw[op]
3
+ .DS_Store
4
+ *.log
5
+ *tmp
6
+ *~
7
+ *#
8
+
9
+ # RVM
10
+ .rvmrc
11
+
12
+ # Don't lock to specific dependencies. Design for incorporation into other projects.
13
+ Gemfile.lock
14
+
15
+ # Gems
16
+ *.gem
17
+
18
+ # IDEs
19
+ .idea
20
+ .project
@@ -0,0 +1,4 @@
1
+ --color
2
+ --backtrace
3
+ --require rspec/instafail
4
+ --format RSpec::Instafail
@@ -0,0 +1,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+
7
+ group :test do
8
+ gem 'rspec', '~> 2.14.1'
9
+ gem 'rspec-instafail', '~> 0.2'
10
+ end
11
+
12
+ group :development, :test do
13
+ gem 'pry'
14
+ end
@@ -0,0 +1,19 @@
1
+ (c) <%= Time.now.year %>, <%= author_name %>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,27 @@
1
+ # <%= service_name %> client
2
+
3
+
4
+ ## Usage
5
+ ```ruby
6
+ client = <%= root_module %>::Client.create()
7
+ service_status = client.status.healthy?
8
+ ```
9
+
10
+
11
+ ## Testing
12
+
13
+ ### this project
14
+ * bundle exec rspec
15
+
16
+ ### from an including project
17
+ In your spec_helper.rb, include the following snippet.
18
+ ```ruby
19
+ <%= root_module %>::Client.stub!
20
+ ```
21
+ This will prevent `<%= project_name %>` from reaching out to live servers.
22
+ Instead, endpoints will return back [local stubbed data](lib/<%= project_name %>/stub.rb).
23
+
24
+
25
+ ## License
26
+ (c) <%= Time.now.year %>, <%= author_name %>
27
+ Released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'saddle'
4
+
5
+ require '<%= project_name %>/exceptions'
6
+ require '<%= project_name %>/middleware/exception_raiser'
7
+ require '<%= project_name %>/stub'
8
+ require '<%= project_name %>/version'
9
+
10
+
11
+
12
+ module <%= root_module %>
13
+
14
+ class Client < Saddle::Client
15
+ extend <%= root_module %>::Stub
16
+
17
+
18
+ # Place default client options here
19
+ # Saddle supports many more options than are listed below. See the documentation.
20
+ #def self.host
21
+ # 'example.org'
22
+ #end
23
+
24
+ #def self.use_ssl
25
+ # true
26
+ #end
27
+
28
+ #def self.num_retries
29
+ # 1
30
+ #end
31
+
32
+ #def self.timeout
33
+ # 5 # seconds
34
+ #end
35
+
36
+ # Raise exceptions, based upon request responses
37
+ add_middleware({
38
+ :klass => Middleware::ExceptionRaiser,
39
+ })
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'saddle/endpoint'
4
+
5
+ module <%= root_module %>
6
+ module Endpoints
7
+
8
+ class Status < Saddle::TraversalEndpoint
9
+
10
+ ABSOLUTE_PATH = ''
11
+
12
+ def healthy?
13
+ get('health') == 'OK'
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ ##
4
+ # Exceptions for using the <%= service_name %> client
5
+ # It is recommended that you handle these.
6
+ ##
7
+
8
+ module <%= root_module %>
9
+
10
+ class GenericException < StandardError; end
11
+
12
+ class TimeoutError < GenericException; end
13
+
14
+ # Some problems might take care of themselves if you try again later. Others won't.
15
+ class TemporaryError < GenericException; end # fire warnings on these
16
+ class PermanentError < GenericException; end # fire errors on these
17
+
18
+ # Implement derivative exception classes here that represent specific errors that the
19
+ # service can throw via status codes or response body
20
+
21
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'faraday'
4
+
5
+ require '<%= project_name %>/exceptions'
6
+
7
+
8
+
9
+ module <%= root_module %>
10
+ module Middleware
11
+
12
+ ## Raise beautiful exceptions
13
+ #
14
+ class ExceptionRaiser < Faraday::Middleware
15
+
16
+ ## For handling errors, the message that gets returned is of the following format:
17
+ # {:status => env[:status], :headers => env[:response_headers], :body => env[:body]}
18
+
19
+ def call(env)
20
+ begin
21
+ @app.call(env)
22
+ rescue Faraday::Error::ClientError => e
23
+ # This is our chance to reinterpret the response into a meaningful, client-specific
24
+ # exception that a consuming service can handle
25
+ exception = <%= root_module %>::GenericException
26
+
27
+ raise exception, e.response
28
+ rescue Saddle::TimeoutError => e
29
+ raise <%= root_module %>::TimeoutError, e.response
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require '<%= project_name %>/endpoints/status'
4
+
5
+ # This allows us to stub out live calls when testing from calling projects
6
+
7
+ module <%= root_module %>
8
+ module Stub
9
+
10
+ # Setup stubbing for all endpoints
11
+ def stub!
12
+ <%= root_module %>::Endpoints::Status.any_instance.stub(:healthy?).and_return(
13
+ Stub::Data::TEST_STATUS_HEALTHY_RESPONSE
14
+ )
15
+ end
16
+
17
+ # Test data for stubs to return
18
+ module Data
19
+
20
+ TEST_STATUS_HEALTHY_RESPONSE = 'OK'.freeze
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module <%= root_module %>
4
+ VERSION = '0.0.0'
5
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/<%= project_name %>/version', __FILE__)
4
+
5
+ lib = File.expand_path('../lib', __FILE__)
6
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = '<%= project_name %>'
10
+ s.version = ::<%= root_module %>::VERSION
11
+ s.authors = ['<%= author_name %>']
12
+ s.email = ['<%= author_email %>']
13
+ s.description = %q{<%= service_name %> client}
14
+ s.summary = %q{
15
+ This is a <%= service_name %> client implemented on Saddle
16
+ }
17
+ s.homepage = 'https://github.com/<%= github_account %>/<%= project_name %>'
18
+ s.license = 'MIT'
19
+
20
+ s.require_path = 'lib'
21
+ s.files = `git ls-files`.split($\)
22
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
24
+
25
+ s.add_dependency 'saddle', '~> <%= saddle_version %>'
26
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ ###
7
+ # NOTE: This spec will actually hit live servers
8
+ ###
9
+
10
+ describe '<%= root_module %>::Endpoints::User' do
11
+ context "Test integration of status endpoints" do
12
+
13
+ let(:client) { <%= root_module %>::Client.create() }
14
+
15
+ it 'should get self profile' do
16
+ client.status.healthy?.should be_true
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe <%= root_module %>::Middleware::ExceptionRaiser do
7
+
8
+ describe "Test raising various exceptions using stubs" do
9
+
10
+ let(:stubs) { Faraday::Adapter::Test::Stubs.new }
11
+ let(:client) { <%= root_module %>::Client.create(:stubs => stubs) }
12
+
13
+
14
+ it 'should detect a service error' do
15
+ stubs.get('/') { [ 500, {}, { 'status' => 'error' } ] }
16
+ expect { client.requester.get('') }.to raise_error(<%= root_module %>::GenericException)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,3 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require '<%= project_name %>'
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+
7
+ describe <%= root_module %>::Stub do
8
+ context 'stubbing out calls' do
9
+
10
+ let(:client) { <%= root_module %>::Client.create }
11
+
12
+ before :each do
13
+ <%= root_module %>::Client.stub!
14
+ end
15
+
16
+ describe 'returns test data' do
17
+ it 'for client.status.healthy?' do
18
+ client.status.healthy?.should be_true
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -68,7 +68,7 @@ module Saddle
68
68
  # Attach the endpoint as an instance variable and method
69
69
  method_name ||= endpoint_class.name.demodulize.underscore
70
70
  self.instance_variable_set("@#{method_name}", endpoint_instance)
71
- self.class.class_eval { define_method(method_name) { endpoint_instance } }
71
+ self.define_singleton_method(method_name.to_s) { endpoint_instance }
72
72
  endpoint_instance
73
73
  end
74
74
 
@@ -132,6 +132,9 @@ module Saddle
132
132
  # traversal tree.
133
133
  class TraversalEndpoint < BaseEndpoint; end
134
134
 
135
+ # This is a special case endpoint for the root node.
136
+ class RootEndpoint < TraversalEndpoint; end
137
+
135
138
 
136
139
  # This endpoint is used for constructing resource-style endpoints. This
137
140
  # means it will NOT be automatically added into the traversal tree.
@@ -44,11 +44,11 @@ module Saddle
44
44
  root_node_class = self.implementation_module::RootEndpoint
45
45
  else
46
46
  # 'root_endpoint.rb' doesn't exist, so create a dummy endpoint
47
- root_node_class = Saddle::TraversalEndpoint
47
+ root_node_class = Saddle::RootEndpoint
48
48
  end
49
49
  else
50
50
  # we don't even have an implementation root, so create a dummy endpoint
51
- root_node_class = Saddle::TraversalEndpoint
51
+ root_node_class = Saddle::RootEndpoint
52
52
  end
53
53
  root_node_class.new(requester, nil, self)
54
54
  end
@@ -1,3 +1,3 @@
1
1
  module Saddle
2
- VERSION = '0.0.43'
2
+ VERSION = '0.0.44'
3
3
  end
@@ -19,8 +19,8 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.require_path = 'lib'
21
21
  s.files = `git ls-files`.split($\)
22
- s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
22
+ s.executables = ['saddle']
23
+ s.test_files = s.files.grep(%r{^(spec)/})
24
24
 
25
25
  s.add_dependency 'activesupport', '>= 3.0'
26
26
  s.add_dependency 'faraday', '~> 0.8.7'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.43
4
+ version: 0.0.44
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-15 00:00:00.000000000 Z
12
+ date: 2013-09-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -61,7 +61,8 @@ dependencies:
61
61
  version: 0.9.0
62
62
  description: Makes writing API clients as easy as giving high fives
63
63
  email: mike.lewis@airbnb.com
64
- executables: []
64
+ executables:
65
+ - saddle
65
66
  extensions: []
66
67
  extra_rdoc_files: []
67
68
  files:
@@ -70,9 +71,25 @@ files:
70
71
  - .travis.yml
71
72
  - CHANGELOG.md
72
73
  - Gemfile
73
- - Gemfile.lock
74
74
  - LICENSE
75
75
  - README.md
76
+ - bin/saddle
77
+ - bin/template/.gitignore
78
+ - bin/template/.rspec
79
+ - bin/template/Gemfile
80
+ - bin/template/LICENSE
81
+ - bin/template/README.md
82
+ - bin/template/lib/saddle-client.rb
83
+ - bin/template/lib/saddle-client/endpoints/status.rb
84
+ - bin/template/lib/saddle-client/exceptions.rb
85
+ - bin/template/lib/saddle-client/middleware/exception_raiser.rb
86
+ - bin/template/lib/saddle-client/stub.rb
87
+ - bin/template/lib/saddle-client/version.rb
88
+ - bin/template/saddle-client.gemspec
89
+ - bin/template/spec/integration/status_spec.rb
90
+ - bin/template/spec/middleware/exception_raiser_spec.rb
91
+ - bin/template/spec/spec_helper.rb
92
+ - bin/template/spec/stub/stub_spec.rb
76
93
  - lib/saddle.rb
77
94
  - lib/saddle/client_attributes.rb
78
95
  - lib/saddle/endpoint.rb
@@ -1,54 +0,0 @@
1
- GEM
2
- remote: https://rubygems.org/
3
- specs:
4
- activesupport (3.2.13)
5
- i18n (= 0.6.1)
6
- multi_json (~> 1.0)
7
- airbrake (3.1.12)
8
- activesupport
9
- builder
10
- json
11
- builder (3.2.0)
12
- coderay (1.0.9)
13
- diff-lcs (1.2.4)
14
- faraday (0.8.7)
15
- multipart-post (~> 1.1)
16
- faraday_middleware (0.9.0)
17
- faraday (>= 0.7.4, < 0.9)
18
- i18n (0.6.1)
19
- json (1.7.7)
20
- method_source (0.8.1)
21
- multi_json (1.7.3)
22
- multipart-post (1.2.0)
23
- pry (0.9.12.2)
24
- coderay (~> 1.0.5)
25
- method_source (~> 0.8)
26
- slop (~> 3.4)
27
- rake (10.1.0)
28
- rspec (2.14.1)
29
- rspec-core (~> 2.14.0)
30
- rspec-expectations (~> 2.14.0)
31
- rspec-mocks (~> 2.14.0)
32
- rspec-core (2.14.2)
33
- rspec-expectations (2.14.0)
34
- diff-lcs (>= 1.1.3, < 2.0)
35
- rspec-instafail (0.2.4)
36
- rspec-mocks (2.14.1)
37
- simple_oauth (0.2.0)
38
- slop (3.4.5)
39
- statsd-ruby (1.2.0)
40
-
41
- PLATFORMS
42
- ruby
43
-
44
- DEPENDENCIES
45
- activesupport (>= 3.0)
46
- airbrake
47
- faraday (~> 0.8.7)
48
- faraday_middleware (~> 0.9.0)
49
- pry
50
- rake
51
- rspec (~> 2.14.1)
52
- rspec-instafail (~> 0.2)
53
- simple_oauth (~> 0.2.0)
54
- statsd-ruby