smoke 0.5.17 → 0.5.19
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/README.markdown +5 -5
- data/Rakefile +1 -0
- data/VERSION.yml +2 -2
- data/lib/core_ext/array.rb +12 -0
- data/lib/smoke.rb +24 -13
- data/lib/smoke/cache.rb +4 -4
- data/lib/smoke/origin.rb +6 -11
- data/lib/smoke/request.rb +5 -14
- data/lib/smoke/transformer.rb +7 -0
- data/lib/smoke/transformers/json.rb +15 -0
- data/lib/smoke/transformers/ruby.rb +11 -0
- data/lib/smoke/{output → transformers}/xml.rb +12 -6
- data/lib/smoke/transformers/yaml.rb +15 -0
- data/spec/smoke/origin_spec.rb +4 -0
- data/spec/smoke/request_spec.rb +7 -0
- data/spec/smoke/{output → transformers}/xml_spec.rb +4 -6
- data/spec/smoke/transformers_spec.rb +35 -0
- data/spec/smoke_spec.rb +18 -10
- data/spec/supports/twitter_timeline.json +22 -0
- metadata +23 -30
- data/rdoc/classes/Smoke.html +0 -260
- data/rdoc/classes/Smoke/Origin.html +0 -340
- data/rdoc/classes/Smoke/Source/Data.html +0 -126
- data/rdoc/classes/Smoke/Source/Feed.html +0 -117
- data/rdoc/classes/Smoke/Source/YQL.html +0 -223
- data/rdoc/created.rid +0 -1
- data/rdoc/files/README_markdown.html +0 -180
- data/rdoc/files/lib/core_ext/hash_rb.html +0 -49
- data/rdoc/files/lib/smoke/origin_rb.html +0 -49
- data/rdoc/files/lib/smoke/request_rb.html +0 -49
- data/rdoc/files/lib/smoke/source/data_rb.html +0 -49
- data/rdoc/files/lib/smoke/source/feed_rb.html +0 -49
- data/rdoc/files/lib/smoke/source/join_rb.html +0 -49
- data/rdoc/files/lib/smoke/source/yql_rb.html +0 -49
- data/rdoc/files/lib/smoke_rb.html +0 -65
- data/rdoc/fr_class_index.html +0 -21
- data/rdoc/fr_file_index.html +0 -28
- data/rdoc/fr_method_index.html +0 -4459
- data/rdoc/index.html +0 -15
- data/rdoc/rdoc-style.css +0 -319
- data/spec/smoke/input/xls_spec.rb +0 -15
- data/spec/smoke/shared_spec.rb +0 -182
- data/spec/supports/gov_act_toliets.xls +0 -0
data/README.markdown
CHANGED
@@ -14,6 +14,7 @@ Then you can output as a plain ruby object or one of your other favourites (JSON
|
|
14
14
|
|
15
15
|
## Media
|
16
16
|
|
17
|
+
* [Presentation from Webjam11 in Perth](http://www.slideshare.net/benschwarz/how-to-reinterpret-the-web-in-180-seconds)
|
17
18
|
* [Presentation from Melbourne #roro](http://www.slideshare.net/benschwarz/smoke-1371124)
|
18
19
|
* Early [screencast](http://vimeo.com/4272804) to get developer / peer feedback
|
19
20
|
|
@@ -77,11 +78,10 @@ Execution:
|
|
77
78
|
|
78
79
|
|
79
80
|
### TODO (working on, just mental notes)
|
80
|
-
|
81
|
-
*
|
82
|
-
*
|
83
|
-
*
|
84
|
-
|
81
|
+
* Items returned from smoke to be Hashie "rich" objects
|
82
|
+
* Output as a web feed (atom, rss)
|
83
|
+
* How to push through values like "author"?
|
84
|
+
* Passing modified time headers through to the atom formatter
|
85
85
|
|
86
86
|
#### For wiki pages (docs, later)
|
87
87
|
* Document all sources with their irrespective differential methods
|
data/Rakefile
CHANGED
@@ -18,6 +18,7 @@ begin
|
|
18
18
|
gem.add_dependency("moneta", "0.6.0")
|
19
19
|
gem.add_dependency("rest-client", "1.0.3")
|
20
20
|
gem.add_dependency("nokogiri", "1.3.2")
|
21
|
+
gem.add_dependency("registry", ">=0.1.2")
|
21
22
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
23
|
end
|
23
24
|
rescue LoadError
|
data/VERSION.yml
CHANGED
data/lib/smoke.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'digest/md5'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
require 'simple-rss'
|
5
6
|
require 'json'
|
@@ -7,8 +8,11 @@ require 'crack'
|
|
7
8
|
require 'moneta'
|
8
9
|
require 'restclient'
|
9
10
|
require 'nokogiri'
|
11
|
+
require 'registry'
|
10
12
|
|
11
|
-
module Smoke
|
13
|
+
module Smoke
|
14
|
+
class NotRegistered < StandardError; end
|
15
|
+
|
12
16
|
class << self
|
13
17
|
@@active_sources = {}
|
14
18
|
@@config = {
|
@@ -22,6 +26,15 @@ module Smoke
|
|
22
26
|
}
|
23
27
|
}
|
24
28
|
|
29
|
+
def root
|
30
|
+
File.join(File.dirname(__FILE__))
|
31
|
+
end
|
32
|
+
|
33
|
+
def version
|
34
|
+
@@version ||= YAML::load(File.read("#{root}/../VERSION.YML"))
|
35
|
+
"#{@@version[:major]}.#{@@version[:minor]}.#{@@version[:patch]}"
|
36
|
+
end
|
37
|
+
|
25
38
|
# Access registered smoke source instances
|
26
39
|
#
|
27
40
|
# Define your source:
|
@@ -39,6 +52,8 @@ module Smoke
|
|
39
52
|
# Usage:
|
40
53
|
# Smoke.twitter(:username => "benschwarz")
|
41
54
|
def method_missing(sym, args = {})
|
55
|
+
raise NotRegistered, "Smoke source not registered" if self[sym].nil?
|
56
|
+
|
42
57
|
args.each_pair {|k, v| self[sym].send(k, v) }
|
43
58
|
self[sym]
|
44
59
|
end
|
@@ -47,8 +62,8 @@ module Smoke
|
|
47
62
|
# Source instances are stored within the
|
48
63
|
# @@active_sources class variable for later use
|
49
64
|
def activate(name, source)
|
50
|
-
if active_sources.
|
51
|
-
Smoke.log.warn "Smoke source activation: Source with
|
65
|
+
if active_sources.key?(name)
|
66
|
+
Smoke.log.warn "Smoke source activation: Source with identical name already initialized"
|
52
67
|
end
|
53
68
|
active_sources.update({ name => source })
|
54
69
|
end
|
@@ -115,15 +130,11 @@ module Smoke
|
|
115
130
|
# end
|
116
131
|
def join(*names, &block); Smoke::Join.new(names, &block); end
|
117
132
|
end
|
133
|
+
|
134
|
+
autoload :YQL, "smoke/source/yql"
|
135
|
+
autoload :Data, "smoke/source/data"
|
136
|
+
autoload :Feed, "smoke/source/feed"
|
137
|
+
autoload :Join, "smoke/source/join"
|
118
138
|
end
|
119
139
|
|
120
|
-
|
121
|
-
|
122
|
-
# Autoload the source classes
|
123
|
-
%w(YQL Data Feed Join).each do |r|
|
124
|
-
Smoke.autoload(r.to_sym, File.join(File.dirname(__FILE__), "smoke", "source", r.downcase))
|
125
|
-
end
|
126
|
-
|
127
|
-
class Object # :nodoc:
|
128
|
-
include Smoke
|
129
|
-
end
|
140
|
+
Dir["#{File.dirname(__FILE__)}/{core_ext,smoke,smoke/transformers}/*.rb"].each {|r| require r}
|
data/lib/smoke/cache.rb
CHANGED
@@ -39,8 +39,8 @@ module Smoke
|
|
39
39
|
|
40
40
|
def query(uri, options)
|
41
41
|
request = RestClient.get(uri, options)
|
42
|
-
write(uri, request, request.headers
|
43
|
-
{:body => request, :
|
42
|
+
write(uri, request, request.headers) if enabled?
|
43
|
+
{:body => request, :headers => request.headers}
|
44
44
|
end
|
45
45
|
|
46
46
|
def read(uri)
|
@@ -48,8 +48,8 @@ module Smoke
|
|
48
48
|
return cache[key]
|
49
49
|
end
|
50
50
|
|
51
|
-
def write(uri, body,
|
52
|
-
store = {:body => body, :
|
51
|
+
def write(uri, body, headers)
|
52
|
+
store = {:body => body, :headers => headers}
|
53
53
|
self.cache.store(generate_key(uri), store, :expire_in => Smoke.config[:cache][:expiry])
|
54
54
|
end
|
55
55
|
|
data/lib/smoke/origin.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Smoke
|
2
2
|
class Origin
|
3
|
+
class UnavailableFormat < StandardError; end
|
4
|
+
|
3
5
|
attr_reader :items, :requirements, :exposed
|
4
6
|
attr_accessor :name
|
5
7
|
|
@@ -13,7 +15,7 @@ module Smoke
|
|
13
15
|
instance_eval(&block) if block_given?
|
14
16
|
end
|
15
17
|
|
16
|
-
# Output your items in a range of formats (:ruby, :json and :yaml currently)
|
18
|
+
# Output your items in a range of formats (:ruby, :json, :xml and :yaml currently)
|
17
19
|
# Ruby is the default format and will automagically yielded from your source
|
18
20
|
#
|
19
21
|
# Usage
|
@@ -24,16 +26,9 @@ module Smoke
|
|
24
26
|
prepare!
|
25
27
|
dispatch if respond_to? :dispatch
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
when :yaml
|
31
|
-
return YAML.dump(@items)
|
32
|
-
when :xml
|
33
|
-
return Smoke::Output::XML.generate(@name, @items)
|
34
|
-
else
|
35
|
-
return @items
|
36
|
-
end
|
29
|
+
Transformer.for(type).generate(name, items)
|
30
|
+
rescue Registry::NotRegistered => e
|
31
|
+
raise UnavailableFormat, e.message
|
37
32
|
end
|
38
33
|
|
39
34
|
def items=(response) # :nodoc:
|
data/lib/smoke/request.rb
CHANGED
@@ -9,7 +9,7 @@ module Smoke
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
SUPPORTED_TYPES = %w(json xml javascript
|
12
|
+
SUPPORTED_TYPES = %w(json xml javascript)
|
13
13
|
@@request_options = {
|
14
14
|
:user_agent => Smoke.config[:user_agent],
|
15
15
|
:accept_encoding => "gzip, deflate"
|
@@ -30,7 +30,7 @@ module Smoke
|
|
30
30
|
def dispatch
|
31
31
|
get = Smoke::Cache.fetch @uri, @@request_options
|
32
32
|
@body = get[:body]
|
33
|
-
@content_type = get[:content_type]
|
33
|
+
@content_type = get[:headers][:content_type]
|
34
34
|
|
35
35
|
parse! unless @options[:raw_response]
|
36
36
|
|
@@ -39,18 +39,9 @@ module Smoke
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def parse!
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
when :xml
|
46
|
-
@body = ::Crack::XML.parse(@body).symbolize_keys!
|
47
|
-
when :excel
|
48
|
-
# Convert the excel document into an XML document
|
49
|
-
doc = @body
|
50
|
-
::Crack::XML.parse().symbolize_keys!
|
51
|
-
when :unknown
|
52
|
-
Smoke.log.warn "Smoke Request: Format unknown for #{@uri} (#{@content_type})"
|
53
|
-
end
|
42
|
+
@body = Transformer.for(type).parse(body).symbolize_keys!
|
43
|
+
rescue Registry::NotRegistered
|
44
|
+
Smoke.log.warn "Smoke Request: Format unknown for #{@uri} (#{@content_type})"
|
54
45
|
end
|
55
46
|
end
|
56
47
|
end
|
@@ -1,23 +1,29 @@
|
|
1
1
|
module Smoke
|
2
|
-
module
|
3
|
-
|
2
|
+
module Transformers
|
3
|
+
class XML < Transformer
|
4
|
+
identifier :xml
|
5
|
+
|
4
6
|
def self.generate(tree_name, items)
|
5
7
|
builder = Nokogiri::XML::Builder.new do |xml|
|
6
8
|
xml.items {
|
7
9
|
items.each do |item|
|
8
10
|
xml.item {
|
9
|
-
%w(id type class).each{|m| item["#{m}_".to_sym] = item.delete(m.to_sym) }
|
10
|
-
|
11
|
+
%w(id type class fork).each{|m| item["#{m}_".to_sym] = item.delete(m.to_sym) }
|
12
|
+
|
11
13
|
item.each do |k, v|
|
12
|
-
xml.
|
14
|
+
xml.__send__(k, v)
|
13
15
|
end
|
14
16
|
}
|
15
17
|
end
|
16
18
|
}
|
17
19
|
end
|
18
|
-
|
20
|
+
|
19
21
|
builder.to_xml
|
20
22
|
end
|
23
|
+
|
24
|
+
def self.parse(string)
|
25
|
+
::Crack::XML.parse(string)
|
26
|
+
end
|
21
27
|
end
|
22
28
|
end
|
23
29
|
end
|
data/spec/smoke/origin_spec.rb
CHANGED
@@ -49,6 +49,10 @@ describe Smoke::Origin do
|
|
49
49
|
Smoke.test.output(:xml).should include "<?xml version=\"1.0\"?>"
|
50
50
|
end
|
51
51
|
|
52
|
+
it "should raise a UnavailableFormat error" do
|
53
|
+
lambda { Smoke.test.output(:xyz) }.should raise_error(Smoke::Origin::UnavailableFormat)
|
54
|
+
end
|
55
|
+
|
52
56
|
describe "filtering" do
|
53
57
|
before :all do
|
54
58
|
TestSource.source(:keep) do
|
data/spec/smoke/request_spec.rb
CHANGED
@@ -35,6 +35,13 @@ describe Smoke::Request do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
it "should handle direct array responses" do
|
39
|
+
url = "http://fake.tld/canned/twitter.json"
|
40
|
+
FakeWeb.register_uri(:get, url, :response => File.join(SPEC_DIR, 'supports', 'twitter_timeline.json'))
|
41
|
+
|
42
|
+
lambda { Smoke::Request.new(url) }.should_not raise_error(NoMethodError)
|
43
|
+
end
|
44
|
+
|
38
45
|
describe "format returns" do
|
39
46
|
it "should have a content type of :manual" do
|
40
47
|
request = Smoke::Request.new(@url, :type => :manual)
|
@@ -1,18 +1,18 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "..", "..", "spec_helper.rb")
|
2
2
|
|
3
|
-
describe Smoke::
|
3
|
+
describe Smoke::Transformers::XML do
|
4
4
|
before do
|
5
5
|
@tree = :tree
|
6
6
|
@items = [
|
7
7
|
{:id => 1, :class => "first", :type => "mammal", :animal => "monkey"},
|
8
8
|
{:id => 2, :class => "second", :type => "mammal", :animal => "elephant"}
|
9
9
|
]
|
10
|
-
@xml = Smoke::
|
10
|
+
@xml = Smoke::Transformers::XML.generate(@tree, @items)
|
11
11
|
@document = Nokogiri::XML(@xml)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should respond to generate" do
|
15
|
-
Smoke::
|
15
|
+
Smoke::Transformers::XML.should respond_to(:generate)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should start the tree off with a named key" do
|
@@ -20,9 +20,7 @@ describe Smoke::Output::XML do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should contain items" do
|
23
|
-
@document.css("
|
24
|
-
item.content.should =~ /monkey/
|
25
|
-
end
|
23
|
+
@document.css("item").size.should == 2
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
describe Smoke::Transformer do
|
4
|
+
describe "parsers" do
|
5
|
+
it "should respond to parse" do
|
6
|
+
Smoke::Transformers::Json.should respond_to(:parse)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond to parse" do
|
10
|
+
Smoke::Transformers::XML.should respond_to(:parse)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should respond to parse" do
|
14
|
+
Smoke::Transformers::Yaml.should respond_to(:parse)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "generators" do
|
19
|
+
it "should respond to generate" do
|
20
|
+
Smoke::Transformers::Json.should respond_to(:generate)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond to generate" do
|
24
|
+
Smoke::Transformers::XML.should respond_to(:generate)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should respond to generate" do
|
28
|
+
Smoke::Transformers::Yaml.should respond_to(:generate)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should respond to generate" do
|
32
|
+
Smoke::Transformers::Ruby.should respond_to(:generate)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/smoke_spec.rb
CHANGED
@@ -6,6 +6,16 @@ describe Smoke do
|
|
6
6
|
@source_b = TestSource.source :b
|
7
7
|
end
|
8
8
|
|
9
|
+
it "should have a root" do
|
10
|
+
Smoke.should respond_to(:root)
|
11
|
+
Smoke.root.should be_an_instance_of(String)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a version string" do
|
15
|
+
Smoke.should respond_to :version
|
16
|
+
Smoke.version.should be_an_instance_of(String)
|
17
|
+
end
|
18
|
+
|
9
19
|
describe "active sources" do
|
10
20
|
it "should allow access to sources via an array accessor" do
|
11
21
|
Smoke[:a].should == @source_a
|
@@ -17,17 +27,15 @@ describe Smoke do
|
|
17
27
|
|
18
28
|
it "should have its name as the hash key" do
|
19
29
|
key = Smoke.active_sources.keys.first
|
20
|
-
Smoke.active_sources[key].name.should == key
|
30
|
+
Smoke.active_sources[key].name.to_s.should == key.to_s
|
21
31
|
end
|
22
32
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
Smoke.b.should raise_error(NoMethodError)
|
30
|
-
end
|
33
|
+
it "should allow access to the sources via a method call" do
|
34
|
+
Smoke.a.should == @source_a
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should throw an error when missing" do
|
38
|
+
lambda { Smoke.frank }.should raise_error(Smoke::NotRegistered)
|
31
39
|
end
|
32
40
|
|
33
41
|
it "should be able to be renamed" do
|
@@ -40,7 +48,7 @@ describe Smoke do
|
|
40
48
|
Smoke[:b].name.should == "b"
|
41
49
|
end
|
42
50
|
end
|
43
|
-
|
51
|
+
|
44
52
|
describe "configuration" do
|
45
53
|
it "should be configurable" do
|
46
54
|
Smoke.should respond_to(:configure)
|