jeff 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # Jeff
2
2
 
3
- **Jeff** is a light-weight module that mixes in client behaviour for [Amazon
4
- Web Services (AWS)][aws]. It wraps the HTTP adapter [Excon][excon] and
5
- implements [Signature Version 2][sign].
3
+ **Jeff** is a light-weight module that mixes in client behaviour for
4
+ [Amazon Web Services (AWS)][aws]. It wraps [Excon][excon], parses
5
+ responses with [Nokogiri][nokogiri], and implements [Signature Version
6
+ 2][sign].
6
7
 
7
8
  ![jeff][jeff]
8
9
 
9
10
  ## Usage
10
11
 
11
- Here's a hypothetical client.
12
+ Build a a hypothetical client.
12
13
 
13
14
  ```ruby
14
15
  class Client
@@ -41,13 +42,17 @@ end
41
42
  You should now be able to access the endpoint.
42
43
 
43
44
  ```ruby
44
- client.post query: {},
45
- body: 'data'
45
+ res = client.post query: {},
46
+ body: 'data'
47
+
48
+ puts res.status # => 200
49
+ puts res.body.root # => { 'Foo' => 'Bar' }
46
50
  ```
47
51
 
48
52
  ### Chunked Requests
49
53
 
50
- You can upload large files performantly by passing a proc that delivers chunks.
54
+ You can upload large files performantly by passing a proc that delivers
55
+ chunks.
51
56
 
52
57
  ```ruby
53
58
  file = File.open 'data'
@@ -57,47 +62,13 @@ client.post query: {},
57
62
  request_block: chunker
58
63
  ```
59
64
 
60
- ### Streaming Responses
61
-
62
- Similarly, you can download and parse large files performantly by passing a
63
- block that will receive chunks.
64
-
65
- ```ruby
66
- streamer = ->(chunk, remaining, total) { puts chunk }
67
-
68
- client.get query: {},
69
- response_block: streamer
70
- ```
71
-
72
- ### Instrumentation
73
-
74
- Requests can be instrumented.
75
-
76
- ```ruby
77
- class Logger
78
- def self.instrument(name, params = {})
79
- $stderr.puts name, params
80
- yield if block_given?
81
- end
82
- end
83
-
84
- client.get query: {}, instrumentor: Logger
85
- ```
86
-
87
- ### Miscellaneous
88
-
89
- * HTTP connections are persistent.
90
- * By default, Jeff will retry failed requests 4 times.
91
-
92
- For more detailed configuration options, read [excon][excon].
93
-
94
65
  ## Compatibility
95
66
 
96
- **Jeff** is Ruby 1.9-compatible. It is tested against [MRI 1.9.3 plus JRuby and
97
- Rubinius in 1.9 mode][travis].
67
+ **Jeff** is compatible with [all Ruby 1.9 flavours][travis].
98
68
 
99
- [aws]: http://aws.amazon.com/
100
- [excon]: https://github.com/geemus/excon
101
- [sign]: http://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
102
- [jeff]: http://f.cl.ly/items/0a3R3J0k1R2f423k1q2l/jeff.jpg
103
- [travis]: http://travis-ci.org/#!/hakanensari/jeff
69
+ [aws]: http://aws.amazon.com/
70
+ [excon]: https://github.com/geemus/excon
71
+ [jeff]: http://f.cl.ly/items/0a3R3J0k1R2f423k1q2l/jeff.jpg
72
+ [nokogiri]: http://nokogiri.org/
73
+ [sign]: http://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
74
+ [travis]: http://travis-ci.org/#!/hakanensari/jeff
@@ -16,7 +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.3'
19
+ gem.add_dependency 'excon', '~> 0.14.0'
20
+ gem.add_dependency 'nokogiri', '~> 1.5'
20
21
  gem.add_development_dependency 'guard-rspec'
21
22
  gem.add_development_dependency 'rake'
22
23
  gem.add_development_dependency 'rspec'
@@ -3,6 +3,7 @@ require 'time'
3
3
  require 'excon'
4
4
 
5
5
  require 'jeff/secret'
6
+ require 'jeff/streamer'
6
7
  require 'jeff/version'
7
8
 
8
9
  module Jeff
@@ -87,9 +88,14 @@ module Jeff
87
88
  # request to Excon.
88
89
  Excon::HTTP_VERBS. each do |method|
89
90
  eval <<-DEF
90
- def #{method}(opts = {}, &block)
91
- opts.update method: :#{method}
92
- connection.request sign opts, &block
91
+ def #{method}(opts = {})
92
+ streamer = Streamer.new
93
+ opts.update method: :#{method},
94
+ response_block: streamer
95
+ res = connection.request sign opts
96
+ res.body = streamer
97
+
98
+ res
93
99
  end
94
100
  DEF
95
101
  end
@@ -0,0 +1,45 @@
1
+ require 'nokogiri'
2
+
3
+ module Jeff
4
+ class Document < Nokogiri::XML::SAX::Document
5
+ def characters(val)
6
+ (node['__content__'] ||= '') << val
7
+ end
8
+
9
+ def end_element(key)
10
+ child = @stack.pop
11
+
12
+ if child.keys == ['__content__']
13
+ child = child['__content__']
14
+ end
15
+
16
+ case node[key]
17
+ when Array
18
+ node[key] << child
19
+ when Hash, String
20
+ node[key] = [node[key], child]
21
+ else
22
+ node[key] = child
23
+ end
24
+ end
25
+
26
+ def start_element(key, attrs = [])
27
+ @stack << {}
28
+ attrs.each { |attr| node.store *attr }
29
+ end
30
+
31
+ def start_document
32
+ @stack = [{}]
33
+ end
34
+
35
+ def root
36
+ @stack.first
37
+ end
38
+
39
+ private
40
+
41
+ def node
42
+ @stack.last
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,22 @@
1
+ require 'jeff/document'
2
+
3
+ module Jeff
4
+ class Streamer
5
+ def initialize
6
+ @parser = Nokogiri::XML::SAX::PushParser.new Document.new
7
+ end
8
+
9
+ def call(chunk, remaining_bytes, total_bytes)
10
+ @parser << chunk.sub(/\n/, '')
11
+ @parser.finish if remaining_bytes == 0
12
+ end
13
+
14
+ def document
15
+ @parser.document
16
+ end
17
+
18
+ def root
19
+ document.root
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module Jeff
2
- VERSION = '0.2.5'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ module Jeff
4
+ describe Document do
5
+ let(:io) do
6
+ StringIO.new %{
7
+ <?xml version=\"1.0\" ?>
8
+ <ItemAttributes>
9
+ <Title>Anti-Oedipus</Title>
10
+ <Author>Gilles Deleuze</Author>
11
+ <Author>Felix Guattari</Author>
12
+ <Creator Role="Translator">Robert Hurley</Creator>
13
+ </ItemAttributes>
14
+ }.strip.gsub />\s+</, '><'
15
+ end
16
+
17
+ let(:doc) { described_class.new }
18
+ let(:parser) { Nokogiri::XML::SAX::Parser.new doc }
19
+
20
+ before do
21
+ io.rewind
22
+ parser.parse io
23
+ end
24
+
25
+ describe '#root' do
26
+ subject { doc.root['ItemAttributes'] }
27
+
28
+ it { should be_a Hash }
29
+
30
+ it 'should handle only children' do
31
+ subject['Title'].should eql 'Anti-Oedipus'
32
+ end
33
+
34
+ it 'should hande arrays' do
35
+ subject['Author'].should be_an Array
36
+ end
37
+
38
+ it 'should handle attributes' do
39
+ creator = subject['Creator']
40
+ creator['Role'].should eql 'Translator'
41
+ creator['__content__'].should eql 'Robert Hurley'
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module Jeff
4
+ describe Streamer do
5
+ let(:streamer) { Streamer.new }
6
+
7
+ let(:xml) do
8
+ %{
9
+ <?xml version="1.0" ?>
10
+ <foo>
11
+ <bar>1</bar>
12
+ </foo>
13
+ }.strip.gsub />\s+</, '><'
14
+ end
15
+
16
+ it 'should parse a stream' do
17
+ bytes_sent = 0
18
+ total_bytes = xml.size
19
+
20
+ xml.scan(/.{1,8}/m).each do |chunk|
21
+ bytes_sent += chunk.size
22
+ streamer.call chunk, total_bytes - bytes_sent, total_bytes
23
+ end
24
+
25
+ streamer.root.should have_key 'foo'
26
+ end
27
+ end
28
+ end
@@ -120,22 +120,18 @@ describe Jeff do
120
120
 
121
121
  Excon::HTTP_VERBS.each do |method|
122
122
  describe "##{method}" do
123
- subject { client.send(method, mock: true).body }
123
+ subject { client.send(method, mock: true).body.root['request'] }
124
124
 
125
125
  before do
126
126
  Excon.stub({ method: method.to_sym }) do |params|
127
- { body: params }
127
+ { body: "<request>#{params[:method]}</request>" }
128
128
  end
129
129
  end
130
130
 
131
131
  after { Excon.stubs.clear }
132
132
 
133
133
  it "should make a #{method.upcase} request" do
134
- subject[:method].should eql method.to_sym
135
- end
136
-
137
- it 'should append a signature' do
138
- subject[:query].should match /.+&Signature=[^&]+$/
134
+ should eql method
139
135
  end
140
136
  end
141
137
  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.5
4
+ version: 0.3.0
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-06 00:00:00.000000000 Z
12
+ date: 2012-07-11 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.3
21
+ version: 0.14.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,23 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.14.3
29
+ version: 0.14.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: nokogiri
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.5'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.5'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: guard-rspec
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -93,9 +109,13 @@ files:
93
109
  - examples/debug.rb
94
110
  - jeff.gemspec
95
111
  - lib/jeff.rb
112
+ - lib/jeff/document.rb
96
113
  - lib/jeff/secret.rb
114
+ - lib/jeff/streamer.rb
97
115
  - lib/jeff/version.rb
116
+ - spec/jeff/document_spec.rb
98
117
  - spec/jeff/secret_spec.rb
118
+ - spec/jeff/streamer_spec.rb
99
119
  - spec/jeff_spec.rb
100
120
  - spec/spec_helper.rb
101
121
  homepage: https://github.com/hakanensari/jeff
@@ -123,7 +143,9 @@ signing_key:
123
143
  specification_version: 3
124
144
  summary: AWS client
125
145
  test_files:
146
+ - spec/jeff/document_spec.rb
126
147
  - spec/jeff/secret_spec.rb
148
+ - spec/jeff/streamer_spec.rb
127
149
  - spec/jeff_spec.rb
128
150
  - spec/spec_helper.rb
129
151
  has_rdoc: