jeff 0.2.4 → 0.2.5

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
@@ -1,2 +1,3 @@
1
1
  Gemfile.lock
2
+ amazon.yml
2
3
  pkg
data/Guardfile CHANGED
@@ -1,4 +1,5 @@
1
1
  guard 'rspec', :cli => '-fd' do
2
+ notification :off
2
3
  watch(%r{^spec/.+_spec\.rb$})
3
4
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
5
  watch('spec/spec_helper.rb') { 'spec' }
data/README.md CHANGED
@@ -76,32 +76,20 @@ Requests can be instrumented.
76
76
  ```ruby
77
77
  class Logger
78
78
  def self.instrument(name, params = {})
79
- if name =~ /request/
80
- $stderr.puts [
81
- params[:scheme],
82
- '://',
83
- params[:host],
84
- '/',
85
- params[:path],
86
- '?',
87
- params[:query]
88
- ].join
89
- yield if block_given?
90
- end
79
+ $stderr.puts name, params
80
+ yield if block_given?
91
81
  end
92
82
  end
93
83
 
94
- client.get query: {},
95
- instrumentor: Logger
84
+ client.get query: {}, instrumentor: Logger
96
85
  ```
97
86
 
98
87
  ### Miscellaneous
99
88
 
100
- HTTP connections are persistent.
89
+ * HTTP connections are persistent.
90
+ * By default, Jeff will retry failed requests 4 times.
101
91
 
102
- By default, Jeff will retry failed requests 4 times.
103
-
104
- For more detailed configuration options, check out [excon][excon].
92
+ For more detailed configuration options, read [excon][excon].
105
93
 
106
94
  ## Compatibility
107
95
 
@@ -0,0 +1,3 @@
1
+ key: foo
2
+ secret: bar
3
+ tag: baz
@@ -0,0 +1,41 @@
1
+ $:.unshift File.expand_path '../../lib', __FILE__
2
+
3
+ require 'yaml'
4
+
5
+ require 'jeff'
6
+ require 'pry'
7
+ require 'pry-doc'
8
+
9
+ class Client
10
+ include Jeff
11
+
12
+ params 'AssociateTag' => -> { tag },
13
+ 'Service' => 'AWSECommerceService',
14
+ 'Version' => '2011-08-01'
15
+
16
+ attr_accessor :tag
17
+
18
+ def initialize
19
+ self.key = config['key']
20
+ self.secret = config['secret']
21
+ self.tag = config['tag']
22
+ self.endpoint = 'http://ecs.amazonaws.com/onca/xml'
23
+ end
24
+
25
+ def find(asins)
26
+ params = {
27
+ 'Operation' => 'ItemLookup',
28
+ 'ItemId' => Array(asins).join(',')
29
+ }
30
+
31
+ get query: params
32
+ end
33
+
34
+ private
35
+
36
+ def config
37
+ @config ||= YAML.load_file File.expand_path '../amazon.yml', __FILE__
38
+ end
39
+ end
40
+
41
+ binding.pry
@@ -16,9 +16,8 @@ Gem::Specification.new do |gem|
16
16
  gem.require_paths = ['lib']
17
17
  gem.version = Jeff::VERSION
18
18
 
19
- gem.add_dependency 'excon', '~> 0.14.2'
19
+ gem.add_dependency 'excon', '~> 0.14.3'
20
20
  gem.add_development_dependency 'guard-rspec'
21
- gem.add_development_dependency 'pry'
22
21
  gem.add_development_dependency 'rake'
23
22
  gem.add_development_dependency 'rspec'
24
23
  end
@@ -1,8 +1,8 @@
1
- require 'base64'
2
1
  require 'time'
3
2
 
4
3
  require 'excon'
5
4
 
5
+ require 'jeff/secret'
6
6
  require 'jeff/version'
7
7
 
8
8
  module Jeff
@@ -10,32 +10,44 @@ module Jeff
10
10
  MissingKey = Class.new ArgumentError
11
11
  MissingSecret = Class.new ArgumentError
12
12
 
13
- SHA256 = OpenSSL::Digest::SHA256.new
14
13
  UNRESERVED = /([^\w.~-]+)/
15
14
 
16
15
  def self.included(base)
17
16
  base.extend ClassMethods
18
17
  end
19
18
 
20
- # Returns an Excon::Connection.
19
+ # Internal: Builds a sorted query.
20
+ #
21
+ # hsh - A hash of query parameters specific to the request.
22
+ #
23
+ # Returns a query String.
24
+ def build_query(hsh)
25
+ default_params
26
+ .merge(hsh)
27
+ .map { |k, v| "#{k}=#{ escape v }" }
28
+ .sort
29
+ .join '&'
30
+ end
31
+
32
+ # Internal: Returns an Excon::Connection.
21
33
  def connection
22
34
  @connection ||= Excon.new endpoint, headers: default_headers,
23
35
  idempotent: true
24
36
  end
25
37
 
26
- # Returns the Hash default request parameters.
38
+ # Internal: Returns the Hash default request parameters.
27
39
  def default_params
28
40
  self.class.params.reduce({}) do |a, (k, v)|
29
41
  a.update k => (v.is_a?(Proc) ? instance_exec(&v) : v)
30
42
  end
31
43
  end
32
44
 
33
- # Returns the Hash default headers.
45
+ # Internal: Returns the Hash default headers.
34
46
  def default_headers
35
47
  self.class.headers
36
48
  end
37
49
 
38
- # Gets the String AWS endpoint.
50
+ # Internal: Gets the String AWS endpoint.
39
51
  #
40
52
  # Raises a MissingEndpoint error if endpoint is missing.
41
53
  def endpoint
@@ -45,7 +57,7 @@ module Jeff
45
57
  # Sets the String AWS endpoint.
46
58
  attr_writer :endpoint
47
59
 
48
- # Gets the String AWS access key id.
60
+ # Internal: Gets the String AWS access key id.
49
61
  #
50
62
  # Raises a MissingKey error if key is missing.
51
63
  def key
@@ -55,15 +67,21 @@ module Jeff
55
67
  # Sets the String AWS access key id.
56
68
  attr_writer :key
57
69
 
58
- # Gets the String AWS secret key.
70
+ # Internal: Gets the Jeff::Secret.
59
71
  #
60
72
  # Raises a MissingSecret error if secret is missing.
61
73
  def secret
62
74
  @secret or raise MissingSecret
63
75
  end
64
76
 
65
- # Sets the String AWS secret key.
66
- attr_writer :secret
77
+ # Sets the AWS secret key.
78
+ #
79
+ # key - A String secret.
80
+ #
81
+ # Returns a Jeff::Secret.
82
+ def secret=(key)
83
+ @secret = Secret.new key
84
+ end
67
85
 
68
86
  # Generate HTTP request verb methods that sign queries and then delegate
69
87
  # request to Excon.
@@ -76,19 +94,6 @@ module Jeff
76
94
  DEF
77
95
  end
78
96
 
79
- # Internal: Builds a sorted query.
80
- #
81
- # hsh - A hash of query parameters specific to the request.
82
- #
83
- # Returns a query String.
84
- def build_query(hsh)
85
- default_params
86
- .merge(hsh)
87
- .map { |k, v| "#{k}=#{ escape v }" }
88
- .sort
89
- .join '&'
90
- end
91
-
92
97
  private
93
98
 
94
99
  def sign(opts)
@@ -96,13 +101,11 @@ module Jeff
96
101
 
97
102
  string_to_sign = [
98
103
  opts[:method].upcase,
99
- opts[:host] || connection.connection[:host],
100
- opts[:path] || connection.connection[:path],
104
+ connection_host,
105
+ opts[:path] || connection_path,
101
106
  query
102
107
  ].join "\n"
103
-
104
- digest = OpenSSL::HMAC.digest SHA256, secret, string_to_sign
105
- signature = Base64.encode64(digest).chomp
108
+ signature = secret.sign string_to_sign
106
109
 
107
110
  opts.update query: [
108
111
  query,
@@ -110,6 +113,14 @@ module Jeff
110
113
  ].join('&')
111
114
  end
112
115
 
116
+ def connection_host
117
+ [connection.connection[:host], connection.connection[:port]].join ':'
118
+ end
119
+
120
+ def connection_path
121
+ connection.connection[:path]
122
+ end
123
+
113
124
  def escape(val)
114
125
  val.to_s.gsub(UNRESERVED) do
115
126
  '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
@@ -0,0 +1,21 @@
1
+ require 'base64'
2
+
3
+ module Jeff
4
+ class Secret
5
+ SHA256 = OpenSSL::Digest::SHA256.new
6
+
7
+ def initialize(key)
8
+ @key = key
9
+ end
10
+
11
+ def sign(message)
12
+ Base64.encode64(digest(message)).chomp
13
+ end
14
+
15
+ private
16
+
17
+ def digest(message)
18
+ OpenSSL::HMAC.digest SHA256, @key, message
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Jeff
2
- VERSION = '0.2.4'
2
+ VERSION = '0.2.5'
3
3
  end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ module Jeff
4
+ describe Secret do
5
+ let(:secret) { Secret.new 'key' }
6
+
7
+ describe '#sign' do
8
+ after { secret.sign 'message' }
9
+
10
+ it 'should digest' do
11
+ secret.should_receive(:digest)
12
+ .and_return double.as_null_object
13
+ end
14
+ it 'should Base64-encode' do
15
+ Base64.should_receive(:encode64)
16
+ .and_return double.as_null_object
17
+ end
18
+ end
19
+ end
20
+ end
@@ -128,6 +128,8 @@ describe Jeff do
128
128
  end
129
129
  end
130
130
 
131
+ after { Excon.stubs.clear }
132
+
131
133
  it "should make a #{method.upcase} request" do
132
134
  subject[:method].should eql method.to_sym
133
135
  end
@@ -151,6 +153,8 @@ describe Jeff do
151
153
  end
152
154
  end
153
155
 
156
+ after { Excon.stubs.clear }
157
+
154
158
  it 'should retry' do
155
159
  client.get(mock: true).status.should be 200
156
160
  end
@@ -1,4 +1,12 @@
1
- require 'pry'
1
+ begin
2
+ require 'pry'
3
+ require 'pry-doc'
4
+ rescue LoadError
5
+ end
2
6
  require 'rspec'
3
7
 
4
8
  require 'jeff'
9
+
10
+ RSpec.configure do |c|
11
+ c.order = :random
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
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: 2012-07-05 00:00:00.000000000 Z
12
+ date: 2012-07-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: excon
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.14.2
21
+ version: 0.14.3
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.14.2
29
+ version: 0.14.3
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: guard-rspec
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -43,22 +43,6 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: pry
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
46
  - !ruby/object:Gem::Dependency
63
47
  name: rake
64
48
  requirement: !ruby/object:Gem::Requirement
@@ -105,9 +89,13 @@ files:
105
89
  - LICENSE
106
90
  - README.md
107
91
  - Rakefile
92
+ - examples/amazon.yml.example
93
+ - examples/debug.rb
108
94
  - jeff.gemspec
109
95
  - lib/jeff.rb
96
+ - lib/jeff/secret.rb
110
97
  - lib/jeff/version.rb
98
+ - spec/jeff/secret_spec.rb
111
99
  - spec/jeff_spec.rb
112
100
  - spec/spec_helper.rb
113
101
  homepage: https://github.com/hakanensari/jeff
@@ -122,18 +110,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
110
  - - ! '>='
123
111
  - !ruby/object:Gem::Version
124
112
  version: '0'
125
- segments:
126
- - 0
127
- hash: 13761434509478082
128
113
  required_rubygems_version: !ruby/object:Gem::Requirement
129
114
  none: false
130
115
  requirements:
131
116
  - - ! '>='
132
117
  - !ruby/object:Gem::Version
133
118
  version: '0'
134
- segments:
135
- - 0
136
- hash: 13761434509478082
137
119
  requirements: []
138
120
  rubyforge_project:
139
121
  rubygems_version: 1.8.23
@@ -141,5 +123,7 @@ signing_key:
141
123
  specification_version: 3
142
124
  summary: AWS client
143
125
  test_files:
126
+ - spec/jeff/secret_spec.rb
144
127
  - spec/jeff_spec.rb
145
128
  - spec/spec_helper.rb
129
+ has_rdoc: