benschwarz-smoke 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -70,13 +70,15 @@ Integrity [is running for smoke](http://integrity.ffolio.net/smoke)
70
70
 
71
71
  ### TODO (working on, just mental notes)
72
72
 
73
- * Implement a disaptch / request method that will actually thread property (event-machine)
73
+ * Secrets
74
74
  * Checkout experimental fakeweb version to stub out the yql specs
75
75
 
76
76
  #### Later / maybe
77
- * Allow for sources to explicitly set the content type being returned for those stupid content providers
78
77
  * YQL w/oAuth
79
78
  * YQL Subqueries?
79
+ * Implement basic auth for sources
80
+ * Allow for sources to explicitly set the content type being returned for those stupid content providers
81
+
80
82
 
81
83
  #### For wiki pages (docs, later)
82
84
  * How to use `path`
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
+ :patch: 7
2
3
  :major: 0
3
4
  :minor: 3
4
- :patch: 6
data/lib/smoke.rb CHANGED
@@ -1,9 +1,9 @@
1
- require 'rubygems'
1
+ require 'zlib'
2
2
  require 'open-uri'
3
3
  require 'logger'
4
- require 'json'
5
4
  require 'crack'
6
5
  require 'simple-rss'
6
+ require 'json'
7
7
 
8
8
  $:<< File.join(File.dirname(__FILE__))
9
9
 
@@ -13,7 +13,10 @@ require 'core_ext/hash.rb'
13
13
  module Smoke
14
14
  class << self
15
15
  @@active_sources = {}
16
- attr_reader :active_sources
16
+ @@config = {
17
+ :enable_logging => true,
18
+ :user_agent => "Ruby/#{RUBY_VERSION}/Smoke"
19
+ }
17
20
 
18
21
  # Access registered smoke source instances
19
22
  #
@@ -58,7 +61,25 @@ module Smoke
58
61
  # Smoke.log.error "message"
59
62
  # Smoke.log.warn "message"
60
63
  def log
61
- @@log ||= Logger.new($stdout)
64
+ @@log ||= Logger.new(config[:enable_logging] ? $stdout : "/dev/null")
65
+ end
66
+
67
+ # Set any configurable options
68
+ #
69
+ # Smoke.configure do |c|
70
+ # c[:user_agent] = "Some other site"
71
+ # end
72
+ #
73
+ def configure(&block)
74
+ yield @@config
75
+ end
76
+
77
+ # Access configuration options
78
+ #
79
+ # Smoke.config[:option_name]
80
+ # => true
81
+ def config
82
+ @@config
62
83
  end
63
84
 
64
85
  def yql(name, &block); Smoke::Source::YQL.new(name, &block); end
data/lib/smoke/origin.rb CHANGED
@@ -34,8 +34,9 @@ module Smoke
34
34
  end
35
35
  end
36
36
 
37
- def items=(items) # :nodoc:
38
- @items = items.flatten.map{|i| i.symbolize_keys! }
37
+ def items=(response) # :nodoc:
38
+ @items = [(@path.nil?) ? response : drill(response, *@path)]
39
+ symbolize_keys!
39
40
  transform!
40
41
  end
41
42
 
@@ -73,6 +74,24 @@ module Smoke
73
74
  @transformation << block
74
75
  end
75
76
 
77
+ # Transform must be used inside an `emit` block.
78
+ # It can be used to alter the a single field at a time
79
+ #
80
+ # Usage:
81
+ # emit do
82
+ # transform :name do |name|
83
+ # name.gsub(/\302/, "")
84
+ # end
85
+ # end
86
+ #
87
+ # In quasi-english: The result of the block is returned and set to each
88
+ # of the :name attributes in the result set.
89
+ def transform(name, &block)
90
+ items.each do |item|
91
+ item[name] = yield(item[name]) || item[name]
92
+ end
93
+ end
94
+
76
95
  # Prepare is used when you'd like to provision for
77
96
  # arguments / variables to be set after the source definition.
78
97
  # Eg, create a source definition for twitter, omitting the "username".
@@ -188,6 +207,10 @@ module Smoke
188
207
  @transformation.each{|t| t.call } unless @transformation.nil?
189
208
  end
190
209
 
210
+ def symbolize_keys!
211
+ @items = items.flatten.map{|i| i.symbolize_keys! } if items.respond_to? :flatten
212
+ end
213
+
191
214
  def drill(*path)
192
215
  path.inject(nil) do |obj, pointer|
193
216
  obj = obj.nil? ? pointer : obj[pointer]
data/lib/smoke/request.rb CHANGED
@@ -20,9 +20,14 @@ module Smoke
20
20
 
21
21
  private
22
22
  def dispatch
23
+ opts = {
24
+ "User-Agent" => Smoke.config[:user_agent],
25
+ "Accept-Encoding" => "gzip"
26
+ }
23
27
  Thread.new {
24
- open(@uri, "User-Agent" => "Ruby/#{RUBY_VERSION}/Smoke") do |request|
28
+ open(@uri, opts) do |request|
25
29
  @content_type = request.content_type
30
+ request = Zlib::GzipReader.new(request) if request.content_encoding.include? "gzip"
26
31
  @body = request.read
27
32
  end
28
33
  }.join
@@ -28,7 +28,7 @@ module Smoke
28
28
  protected
29
29
  def dispatch
30
30
  @request = Smoke::Request.new(@url)
31
- self.items = (@path.nil?) ? @request.body : drill(@request.body, *@path)
31
+ self.items = @request.body
32
32
  end
33
33
  end
34
34
  end
@@ -6,7 +6,6 @@ module Smoke
6
6
  #
7
7
  # Usage:
8
8
  # Smoke.join(:delicious, :twitter, :flickr) do
9
- # name :stream
10
9
  # path :photos, :photo
11
10
  # end
12
11
  class Join < Origin # :nodoc:
@@ -63,7 +63,7 @@ module Smoke
63
63
 
64
64
  def dispatch
65
65
  @request = Smoke::Request.new(build_uri)
66
- self.items = [(@path.nil?) ? @request.body : drill(@request.body, *@path)]
66
+ self.items = @request.body
67
67
  end
68
68
 
69
69
  private
@@ -6,6 +6,10 @@ describe Smoke::Origin do
6
6
  emit do
7
7
  rename(:head => :title)
8
8
  sort(:title)
9
+
10
+ transform :title do |title|
11
+ title.gsub(/Animal: /, '')
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -43,8 +47,21 @@ describe Smoke::Origin do
43
47
 
44
48
  describe "filtering" do
45
49
  before do
46
- TestSource.source(:keep)
47
- TestSource.source(:discard)
50
+ TestSource.source(:keep) do
51
+ emit do
52
+ transform :head do |head|
53
+ head.gsub(/Animal: /, '')
54
+ end
55
+ end
56
+ end
57
+
58
+ TestSource.source(:discard) do
59
+ emit do
60
+ transform :head do |head|
61
+ head.gsub(/Animal: /, '')
62
+ end
63
+ end
64
+ end
48
65
  end
49
66
 
50
67
  it "should keep items" do
@@ -93,12 +110,18 @@ describe Smoke::Origin do
93
110
  end
94
111
 
95
112
  it "method chaining" do
96
- @source = TestSource.source(:chain)
97
- @source.rename(:head => :header).sort(:header).output.should == [{:header => "Kangaroo"}, {:header => "Platypus"}]
113
+ TestSource.source(:chain) do
114
+ emit do
115
+ transform :head do |head|
116
+ head.gsub(/Animal: /, '')
117
+ end
118
+ end
119
+ end
120
+ Smoke[:chain].rename(:head => :header).sort(:header).output.should == [{:header => "Kangaroo"}, {:header => "Platypus"}]
98
121
  end
99
122
 
100
123
  it "should softly error when attempting to sort on a key that doesn't exist" do
101
- TestSource.source(:chain).sort(:header).should_not raise_error("NoMethodError")
124
+ Smoke[:chain].sort(:header).should_not raise_error("NoMethodError")
102
125
  end
103
126
 
104
127
  describe "preperation" do
@@ -114,51 +137,65 @@ describe Smoke::Origin do
114
137
  lambda { @source.prepare }.should raise_error
115
138
  lambda { @source.prepare {} }.should_not raise_error
116
139
  end
117
-
118
- describe "call order" do
119
- before :all do
120
- @url = "http://domain.tld/benschwarz/feed"
121
- FakeWeb.register_uri(@url, :response => File.join(SPEC_DIR, 'supports', 'flickr-photo.json'))
122
-
123
- Smoke.data :feed_preperation_call_order do
124
- prepare do
125
- url "http://domain.tld/#{username}/feed"
126
- end
127
-
128
- path :photos, :photo
140
+ end
141
+
142
+ describe "call order" do
143
+ before :all do
144
+ @url = "http://domain.tld/benschwarz/feed"
145
+ FakeWeb.register_uri(@url, :response => File.join(SPEC_DIR, 'supports', 'flickr-photo.json'))
146
+
147
+ Smoke.data :feed_preperation_call_order do
148
+ prepare do
149
+ url "http://domain.tld/#{username}/feed"
129
150
  end
151
+
152
+ path :photos, :photo
153
+ end
154
+ end
155
+
156
+ describe "before setting variables" do
157
+ it "should fail" do
158
+ lambda { Smoke[:feed_preperation_call_order].output }.should raise_error(NameError)
159
+ end
160
+ end
161
+
162
+ describe "setting abstract properties" do
163
+ it "should not respond to a property that hasn't been set" do
164
+ lambda { Smoke[:feed_preperation_call_order].abstract }.should raise_error(NoMethodError)
130
165
  end
131
166
 
132
- describe "before setting variables" do
133
- it "should fail" do
134
- lambda { Smoke[:feed_preperation_call_order].output }.should raise_error(NameError)
135
- end
167
+ it "should allow setting a property" do
168
+ lambda { Smoke[:feed_preperation_call_order].abstract(:value) }.should_not raise_error(NoMethodError)
169
+ Smoke[:feed_preperation_call_order].abstract.should == :value
136
170
  end
137
171
 
138
- describe "setting abstract properties" do
139
- it "should not respond to a property that hasn't been set" do
140
- lambda { Smoke[:feed_preperation_call_order].abstract }.should raise_error(NoMethodError)
141
- end
142
-
143
- it "should allow setting a property" do
144
- lambda { Smoke[:feed_preperation_call_order].abstract(:value) }.should_not raise_error(NoMethodError)
145
- Smoke[:feed_preperation_call_order].abstract.should == :value
146
- end
147
-
148
- it "should chain the source when setting a property" do
149
- Smoke[:feed_preperation_call_order].abstract(:value).should be_an_instance_of(Smoke::Source::Data)
150
- end
172
+ it "should chain the source when setting a property" do
173
+ Smoke[:feed_preperation_call_order].abstract(:value).should be_an_instance_of(Smoke::Source::Data)
174
+ end
175
+ end
176
+
177
+ describe "after setting variables" do
178
+ it "should output successfully" do
179
+ lambda { Smoke[:feed_preperation_call_order].username("benschwarz").output }.should_not raise_error
151
180
  end
152
181
 
153
- describe "after setting variables" do
154
- it "should output successfully" do
155
- lambda { Smoke[:feed_preperation_call_order].username("benschwarz").output }.should_not raise_error
156
- end
157
-
158
- it "should have used the correct url" do
159
- Smoke[:feed_preperation_call_order].request.uri.should == @url
160
- end
182
+ it "should have used the correct url" do
183
+ Smoke[:feed_preperation_call_order].request.uri.should == @url
161
184
  end
162
185
  end
163
186
  end
187
+
188
+ describe "trasformations" do
189
+ it "should respond to emit" do
190
+ Smoke[:test].should respond_to(:emit)
191
+ end
192
+
193
+ it "should respond to transform" do
194
+ Smoke[:test].should respond_to(:transform)
195
+ end
196
+
197
+ it "should have at least one transformation" do
198
+ Smoke[:test].transformation.size.should == 1
199
+ end
200
+ end
164
201
  end
@@ -22,13 +22,33 @@ describe Smoke::Request do
22
22
 
23
23
  it "should be a pure ruby array response" do
24
24
  # Temporary real request, fakeweb isn't allowing content_type setting as of writing
25
- @request = Smoke::Request.new("http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20search.web%20WHERE%20query%20=%20'ruby'&format=xml")
26
- @request.body.should be_an_instance_of(Hash)
25
+ request = Smoke::Request.new("http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20search.web%20WHERE%20query%20=%20'ruby'&format=xml")
26
+ request.body.should be_an_instance_of(Hash)
27
27
  end
28
28
 
29
29
  it "should be a raw string response" do
30
- @request = Smoke::Request.new(@url, :raw_response)
31
- @request.body.should be_an_instance_of(String)
30
+ request = Smoke::Request.new(@url, :raw_response)
31
+ request.body.should be_an_instance_of(String)
32
+ end
33
+
34
+ describe "gzipped responses" do
35
+ before do
36
+ # class Stream < StringIO
37
+ # def close; rewind; end
38
+ # end
39
+ # output = Stream.new
40
+ # gz = Zlib::GzipWriter.new(output)
41
+ # gz.write(File.read(@gzip_response))
42
+ # gz.close
43
+ #@gzip_response = File.join(SPEC_DIR, 'supports', 'gzip.response')
44
+ #FakeWeb.register_uri(@url, :file => @gzip_response)
45
+ end
46
+
47
+ it "should transparently handle a gzipped response" do
48
+ pending
49
+ request = Smoke::Request.new(@url)
50
+ request.body.should == "gzip_response"
51
+ end
32
52
  end
33
53
 
34
54
  describe "http redirects" do
data/spec/smoke_spec.rb CHANGED
@@ -17,4 +17,31 @@ describe Smoke do
17
17
  Smoke[:b].should be_an_instance_of(Smoke::Origin)
18
18
  end
19
19
  end
20
+
21
+ describe "configuration" do
22
+ it "should be configurable" do
23
+ Smoke.should respond_to(:configure)
24
+ end
25
+
26
+ it "should be accessible" do
27
+ Smoke.should respond_to(:config)
28
+ end
29
+
30
+ it "should take a block and be retrievable" do
31
+ Smoke.configure {|c| c[:spec] = true }
32
+ Smoke.config[:spec].should be_true
33
+ end
34
+
35
+ describe "default configurations" do
36
+ it "should have at least one default configuration" do
37
+ Smoke.config.keys.should_not be_empty
38
+ end
39
+
40
+ it "should allow overwriting default configurations" do
41
+ key = Smoke.config.keys.first
42
+ Smoke.configure {|c| c[key] = true }
43
+ Smoke.config[key].should be_true
44
+ end
45
+ end
46
+ end
20
47
  end
data/spec/spec_helper.rb CHANGED
@@ -13,4 +13,8 @@ $:<< SPEC_DIR
13
13
  require 'smoke'
14
14
 
15
15
  require 'supports/mayo.rb'
16
- require 'supports/test_source.rb'
16
+ require 'supports/test_source.rb'
17
+
18
+ Smoke.configure do |c|
19
+ c[:enable_logging] = false
20
+ end
@@ -2,8 +2,8 @@ module TestSource
2
2
  def self.source(name, &block)
3
3
  source = Smoke::Origin.new(name, &block || Proc.new {})
4
4
  source.items = [
5
- {:head => "Platypus"},
6
- {:head => "Kangaroo"}
5
+ {:head => "Animal: Platypus"},
6
+ {:head => "Animal: Kangaroo"}
7
7
  ]
8
8
  return source
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: benschwarz-smoke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Schwarz
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-09 00:00:00 -07:00
12
+ date: 2009-06-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -100,7 +100,7 @@ requirements: []
100
100
  rubyforge_project:
101
101
  rubygems_version: 1.2.0
102
102
  signing_key:
103
- specification_version: 3
103
+ specification_version: 2
104
104
  summary: smoke is a DSL that allows you to take data from YQL, RSS / Atom
105
105
  test_files: []
106
106