benschwarz-smoke 0.2.4 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +2 -2
- data/VERSION.yml +1 -1
- data/lib/smoke/origin.rb +44 -7
- data/lib/smoke/source/data.rb +28 -36
- data/lib/smoke/source/feed.rb +15 -23
- data/lib/smoke/source/yql.rb +74 -82
- data/lib/smoke.rb +10 -17
- data/spec/smoke/origin_spec.rb +59 -4
- data/spec/smoke/source/data_spec.rb +1 -1
- data/spec/smoke/source/feed_spec.rb +1 -1
- data/spec/smoke/source/yql_spec.rb +13 -3
- data/spec/smoke_spec.rb +0 -14
- metadata +2 -3
- data/lib/smoke/delayed_block.rb +0 -9
data/README.markdown
CHANGED
@@ -56,8 +56,8 @@ Integrity [is running for smoke](http://integrity.ffolio.net/smoke)
|
|
56
56
|
|
57
57
|
### TODO (working on, just mental notes)
|
58
58
|
|
59
|
-
*
|
60
|
-
*
|
59
|
+
* Joined sources require a call to dispatch when their parent calls output
|
60
|
+
* Sources that are renamed also need their @name's renaming
|
61
61
|
* Implement a disaptch / request method that will actually thread property (event-machine)
|
62
62
|
* Checkout experimental fakeweb version to stub out the yql specs
|
63
63
|
|
data/VERSION.yml
CHANGED
data/lib/smoke/origin.rb
CHANGED
@@ -5,7 +5,7 @@ module Smoke
|
|
5
5
|
def initialize(name, &block)
|
6
6
|
raise StandardError, "Sources must have a name" unless name
|
7
7
|
@name = name
|
8
|
-
@items, @transformation = [], []
|
8
|
+
@items, @prepare, @transformation = [], [], []
|
9
9
|
|
10
10
|
activate!
|
11
11
|
instance_eval(&block) if block_given?
|
@@ -19,22 +19,23 @@ module Smoke
|
|
19
19
|
# output(:json)
|
20
20
|
# => "[{title: \"Ray\"}, {title: \"Peace\"}]"
|
21
21
|
def output(type = :ruby)
|
22
|
+
prepare!
|
22
23
|
dispatch if respond_to? :dispatch
|
23
24
|
output = (@items.length == 1) ? @items.first : @items
|
24
25
|
|
25
26
|
case type
|
26
|
-
when :ruby
|
27
|
-
return output
|
28
27
|
when :json
|
29
28
|
return ::JSON.generate(output)
|
30
29
|
when :yaml
|
31
30
|
return YAML.dump(output)
|
31
|
+
else
|
32
|
+
return output
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
36
|
def items=(items) # :nodoc:
|
36
37
|
@items = items.flatten.map{|i| i.symbolize_keys! }
|
37
|
-
|
38
|
+
transform!
|
38
39
|
end
|
39
40
|
|
40
41
|
# Path allows you to traverse the tree of a the items returned to
|
@@ -68,7 +69,39 @@ module Smoke
|
|
68
69
|
# rename(:href => :link)
|
69
70
|
# end
|
70
71
|
def emit(&block)
|
71
|
-
@transformation <<
|
72
|
+
@transformation << block
|
73
|
+
end
|
74
|
+
|
75
|
+
# Prepare is used when you'd like to provision for
|
76
|
+
# arguments / variables to be set after the source definition.
|
77
|
+
# Eg, create a source definition for twitter, omitting the "username".
|
78
|
+
# Set the username using chaining later.
|
79
|
+
#
|
80
|
+
# Usage:
|
81
|
+
# # Definition
|
82
|
+
# Smoke.feed :twitter do
|
83
|
+
# prepare do
|
84
|
+
# url "http://twitter.com/#{username}/rss"
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # End use
|
89
|
+
# Smoke[:twitter].username(:benschwarz).output
|
90
|
+
def prepare(&block)
|
91
|
+
raise ArgumentError, "requires a block" unless block_given?
|
92
|
+
@prepare << block
|
93
|
+
end
|
94
|
+
|
95
|
+
def method_missing(symbol, *args, &block)
|
96
|
+
ivar = "@#{symbol}"
|
97
|
+
|
98
|
+
if args.empty?
|
99
|
+
return instance_variable_get(ivar) || super
|
100
|
+
else
|
101
|
+
instance_variable_set(ivar, args.pop)
|
102
|
+
end
|
103
|
+
|
104
|
+
return self
|
72
105
|
end
|
73
106
|
|
74
107
|
# Re-sort items by a particular key
|
@@ -134,8 +167,12 @@ module Smoke
|
|
134
167
|
end
|
135
168
|
|
136
169
|
private
|
137
|
-
def
|
138
|
-
@
|
170
|
+
def prepare!
|
171
|
+
@prepare.each{|p| p.call } unless @prepare.nil?
|
172
|
+
end
|
173
|
+
|
174
|
+
def transform!
|
175
|
+
@transformation.each{|t| t.call } unless @transformation.nil?
|
139
176
|
end
|
140
177
|
|
141
178
|
def drill(*path)
|
data/lib/smoke/source/data.rb
CHANGED
@@ -1,42 +1,34 @@
|
|
1
1
|
module Smoke
|
2
|
-
module Source # :nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
module Source # :nodoc:
|
3
|
+
# The "Data" source allows you to query
|
4
|
+
# datasources that are "complete" urls
|
5
|
+
# and rely on the automagic object parsing
|
6
|
+
# that smoke provides.
|
7
|
+
#
|
8
|
+
# For example, you may use this source
|
9
|
+
# to query a complete restful api call
|
10
|
+
# unpackage the xml response and get a
|
11
|
+
# clean ruby object.
|
12
|
+
#
|
13
|
+
# Data can take as many urls as you'd like
|
14
|
+
# to throw at it.
|
15
|
+
#
|
16
|
+
# Usage:
|
17
|
+
# Smoke.data(:ruby) do
|
18
|
+
# url "http://api.flickr.com/services/rest/?user_id=36821533%40N00&tags=benschwarz-site&nojsoncallback=1&method=flickr.photos.search&format=json&api_key=your_api_key_here
|
19
|
+
# path :photos, :photo
|
20
|
+
# end
|
21
|
+
class Data < Origin
|
22
|
+
attr_reader :request
|
23
|
+
|
24
|
+
def url(source_url)
|
25
|
+
@url = source_url
|
8
26
|
end
|
9
27
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
# For example, you may use this source
|
16
|
-
# to query a complete restful api call
|
17
|
-
# unpackage the xml response and get a
|
18
|
-
# clean ruby object.
|
19
|
-
#
|
20
|
-
# Data can take as many urls as you'd like
|
21
|
-
# to throw at it.
|
22
|
-
#
|
23
|
-
# Usage:
|
24
|
-
# Smoke.data(:ruby) do
|
25
|
-
# url "http://api.flickr.com/services/rest/?user_id=36821533%40N00&tags=benschwarz-site&nojsoncallback=1&method=flickr.photos.search&format=json&api_key=your_api_key_here
|
26
|
-
# path :photos, :photo
|
27
|
-
# end
|
28
|
-
class Data < Origin
|
29
|
-
attr_reader :request
|
30
|
-
|
31
|
-
def url(source_url)
|
32
|
-
@url = source_url
|
33
|
-
end
|
34
|
-
|
35
|
-
protected
|
36
|
-
def dispatch
|
37
|
-
@request = Smoke::Request.new(@url)
|
38
|
-
self.items = (@path.nil?) ? @request.body : drill(@request.body, *@path)
|
39
|
-
end
|
28
|
+
protected
|
29
|
+
def dispatch
|
30
|
+
@request = Smoke::Request.new(@url)
|
31
|
+
self.items = (@path.nil?) ? @request.body : drill(@request.body, *@path)
|
40
32
|
end
|
41
33
|
end
|
42
34
|
end
|
data/lib/smoke/source/feed.rb
CHANGED
@@ -1,31 +1,23 @@
|
|
1
1
|
module Smoke
|
2
2
|
module Source # :nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
# Feed can take multiple rss or atom feeds and munge them up together.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# Smoke.feed(:ruby) do
|
7
|
+
# url "domain.tld/rss"
|
8
|
+
# url "site.tld/atom"
|
9
|
+
# end
|
10
|
+
class Feed < Origin
|
11
|
+
attr_reader :requests
|
5
12
|
|
6
|
-
def
|
7
|
-
|
13
|
+
def url(feed_uri)
|
14
|
+
(@feeds ||= [] ) << feed_uri
|
8
15
|
end
|
9
16
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# url "domain.tld/rss"
|
15
|
-
# url "site.tld/atom"
|
16
|
-
# end
|
17
|
-
class Feed < Origin
|
18
|
-
attr_reader :requests
|
19
|
-
|
20
|
-
def url(feed_uri)
|
21
|
-
(@feeds ||= [] ) << feed_uri
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
def dispatch
|
26
|
-
@requests = @feeds.map{|f| Smoke::Request.new(f, :raw_response) }
|
27
|
-
self.items = @requests.map{|r| ::SimpleRSS.parse(r.body).items }.flatten
|
28
|
-
end
|
17
|
+
protected
|
18
|
+
def dispatch
|
19
|
+
@requests = @feeds.map{|f| Smoke::Request.new(f, :raw_response) }
|
20
|
+
self.items = @requests.map{|r| ::SimpleRSS.parse(r.body).items }.flatten
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
data/lib/smoke/source/yql.rb
CHANGED
@@ -1,92 +1,84 @@
|
|
1
1
|
module Smoke
|
2
|
-
module Source # :nodoc:
|
3
|
-
|
4
|
-
|
2
|
+
module Source # :nodoc:
|
3
|
+
# YQL will call to Yahoo YQL services
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# Smoke.yql(:ruby) do
|
7
|
+
# select :all
|
8
|
+
# from "search.web"
|
9
|
+
# where :query, "ruby"
|
10
|
+
# end
|
11
|
+
class YQL < Origin
|
12
|
+
API_BASE = "http://query.yahooapis.com/v1/public/yql"
|
13
|
+
attr_reader :request
|
5
14
|
|
6
|
-
|
7
|
-
|
15
|
+
# Select indicates what YQL will be selecting
|
16
|
+
# Usage:
|
17
|
+
# select :all
|
18
|
+
# => "SELECT *"
|
19
|
+
# select :title
|
20
|
+
# => "SELECT title"
|
21
|
+
# select :title, :description
|
22
|
+
# => "SELECT title, description"
|
23
|
+
def select(what = :all)
|
24
|
+
@select = what.join(",") and return if what.is_a? Array
|
25
|
+
@select = "*" and return if what == :all
|
26
|
+
@select = what.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
# from corresponds to the from fragment of the YQL query
|
30
|
+
# Usage:
|
31
|
+
# from "search.web"
|
32
|
+
# or
|
33
|
+
# from :html
|
34
|
+
def from(source)
|
35
|
+
@from = source.join(',') and return if source.is_a? Array
|
36
|
+
@from = source.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
# where is a straight up match, no fancy matchers
|
40
|
+
# are currently supported
|
41
|
+
# Usage:
|
42
|
+
# where :xpath, "//div/div/a"
|
43
|
+
# or
|
44
|
+
# where :query, "python"
|
45
|
+
def where(column, value)
|
46
|
+
@where = @where || []
|
47
|
+
@where << "#{column.to_s} = '#{value}'"
|
8
48
|
end
|
9
49
|
|
10
|
-
#
|
50
|
+
# `use` can be used to set the url location of the data-table
|
51
|
+
# that you want YQL to search upon
|
11
52
|
#
|
12
53
|
# Usage:
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# from corresponds to the from fragment of the YQL query
|
37
|
-
# Usage:
|
38
|
-
# from "search.web"
|
39
|
-
# or
|
40
|
-
# from :html
|
41
|
-
def from(source)
|
42
|
-
@from = source.join(',') and return if source.is_a? Array
|
43
|
-
@from = source.to_s
|
44
|
-
end
|
45
|
-
|
46
|
-
# where is a straight up match, no fancy matchers
|
47
|
-
# are currently supported
|
48
|
-
# Usage:
|
49
|
-
# where :xpath, "//div/div/a"
|
50
|
-
# or
|
51
|
-
# where :query, "python"
|
52
|
-
def where(column, value)
|
53
|
-
@where = @where || []
|
54
|
-
@where << "#{column.to_s} = '#{value}'"
|
55
|
-
end
|
56
|
-
|
57
|
-
# `use` can be used to set the url location of the data-table
|
58
|
-
# that you want YQL to search upon
|
59
|
-
#
|
60
|
-
# Usage:
|
61
|
-
# use "http://datatables.org/alltables.env"
|
62
|
-
def use(url)
|
63
|
-
params.merge!({:env => url})
|
64
|
-
end
|
65
|
-
|
66
|
-
protected
|
67
|
-
def params
|
68
|
-
@params || @params = {}
|
69
|
-
end
|
70
|
-
|
71
|
-
def dispatch
|
72
|
-
@request = Smoke::Request.new(build_uri)
|
73
|
-
self.items = [(@path.nil?) ? @request.body : drill(@request.body, *@path)]
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
def build_uri
|
78
|
-
chunks = []
|
79
|
-
default_opts = {
|
80
|
-
:q => build_query,
|
81
|
-
:format => "json"
|
82
|
-
}.merge(params).each {|k,v| chunks << "#{k}=#{v}" }
|
83
|
-
|
84
|
-
return URI.encode(API_BASE + "?" + chunks.join("&"))
|
85
|
-
end
|
54
|
+
# use "http://datatables.org/alltables.env"
|
55
|
+
def use(url)
|
56
|
+
params.merge!({:env => url})
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
def params
|
61
|
+
@params || @params = {}
|
62
|
+
end
|
63
|
+
|
64
|
+
def dispatch
|
65
|
+
@request = Smoke::Request.new(build_uri)
|
66
|
+
self.items = [(@path.nil?) ? @request.body : drill(@request.body, *@path)]
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def build_uri
|
71
|
+
chunks = []
|
72
|
+
default_opts = {
|
73
|
+
:q => build_query,
|
74
|
+
:format => "json"
|
75
|
+
}.merge(params).each {|k,v| chunks << "#{k}=#{v}" }
|
86
76
|
|
87
|
-
|
88
|
-
|
89
|
-
|
77
|
+
return URI.encode(API_BASE + "?" + chunks.join("&"))
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_query
|
81
|
+
"SELECT #{@select} FROM #{@from} WHERE #{@where.join(" AND ")}"
|
90
82
|
end
|
91
83
|
end
|
92
84
|
end
|
data/lib/smoke.rb
CHANGED
@@ -5,28 +5,16 @@ require 'json'
|
|
5
5
|
require 'crack'
|
6
6
|
require 'simple-rss'
|
7
7
|
|
8
|
-
|
9
8
|
$:<< File.join(File.dirname(__FILE__))
|
10
9
|
|
11
10
|
# Core ext
|
12
11
|
require 'core_ext/hash.rb'
|
13
12
|
|
14
13
|
module Smoke
|
15
|
-
class << self
|
16
|
-
|
14
|
+
class << self
|
17
15
|
@@active_sources = {}
|
18
16
|
attr_reader :active_sources
|
19
17
|
|
20
|
-
# Smoke sources can invoke access to themselves
|
21
|
-
# via the register method:
|
22
|
-
#
|
23
|
-
# Smoke.register(Smoke::Source::YQL)
|
24
|
-
#
|
25
|
-
# Check the supplied sources for usage
|
26
|
-
def register(mod)
|
27
|
-
class_eval { include mod }
|
28
|
-
end
|
29
|
-
|
30
18
|
# Access registered smoke source instances
|
31
19
|
#
|
32
20
|
# Usage:
|
@@ -34,7 +22,7 @@ module Smoke
|
|
34
22
|
# Smoke.yql(:ruby) do ....
|
35
23
|
#
|
36
24
|
# Smoke[:ruby]
|
37
|
-
# => #<Smoke::Source::YQL::
|
25
|
+
# => #<Smoke::Source::YQL::0x18428d4...
|
38
26
|
def [](source)
|
39
27
|
active_sources[source]
|
40
28
|
end
|
@@ -49,11 +37,13 @@ module Smoke
|
|
49
37
|
return source
|
50
38
|
end
|
51
39
|
|
40
|
+
# Activates new instances of sources
|
41
|
+
# Source instances are stored within the
|
42
|
+
# @@active_sources class variable for later use
|
52
43
|
def activate(name, source)
|
53
44
|
if active_sources.has_key?(name)
|
54
45
|
Smoke.log.warn "Smoke source activation: Source with idential name already initialized"
|
55
46
|
end
|
56
|
-
|
57
47
|
active_sources.update({ name => source })
|
58
48
|
end
|
59
49
|
|
@@ -77,9 +67,13 @@ module Smoke
|
|
77
67
|
# Smoke.log.error "message"
|
78
68
|
# Smoke.log.warn "message"
|
79
69
|
def log
|
80
|
-
|
70
|
+
@@log ||= Logger.new($stdout)
|
81
71
|
end
|
82
72
|
|
73
|
+
def yql(name, &block); Smoke::Source::YQL.new(name, &block); end
|
74
|
+
def data(name, &block); Smoke::Source::Data.new(name, &block); end
|
75
|
+
def feed(name, &block); Smoke::Source::Feed.new(name, &block); end
|
76
|
+
|
83
77
|
private
|
84
78
|
def get_sources(sources = [])
|
85
79
|
active_sources.find_all{|k, v| sources.include?(k) }
|
@@ -89,7 +83,6 @@ end
|
|
89
83
|
|
90
84
|
require 'smoke/request'
|
91
85
|
require 'smoke/origin'
|
92
|
-
require 'smoke/delayed_block'
|
93
86
|
|
94
87
|
class Object # :nodoc:
|
95
88
|
include Smoke
|
data/spec/smoke/origin_spec.rb
CHANGED
@@ -97,9 +97,64 @@ describe Smoke::Origin do
|
|
97
97
|
TestSource.source(:chain).sort(:header).should_not raise_error("NoMethodError")
|
98
98
|
end
|
99
99
|
|
100
|
-
describe "
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
describe "preperation" do
|
101
|
+
before :all do
|
102
|
+
@source = TestSource.source(:preperation)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should respond to prepare" do
|
106
|
+
@source.should respond_to(:prepare)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should require a block" do
|
110
|
+
lambda { @source.prepare }.should raise_error
|
111
|
+
lambda { @source.prepare {} }.should_not raise_error
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "call order" do
|
115
|
+
before :all do
|
116
|
+
@url = "http://domain.tld/benschwarz/feed"
|
117
|
+
FakeWeb.register_uri(@url, :response => File.join(SPEC_DIR, 'supports', 'flickr-photo.json'))
|
118
|
+
|
119
|
+
Smoke.data :feed_preperation_call_order do
|
120
|
+
prepare do
|
121
|
+
url "http://domain.tld/#{username}/feed"
|
122
|
+
end
|
123
|
+
|
124
|
+
path :photos, :photo
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "before setting variables" do
|
129
|
+
it "should fail" do
|
130
|
+
lambda { Smoke[:feed_preperation_call_order].output }.should raise_error(NameError)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "setting abstract properties" do
|
135
|
+
it "should not respond to a property that hasn't been set" do
|
136
|
+
lambda { Smoke[:feed_preperation_call_order].abstract }.should raise_error(NoMethodError)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should allow setting a property" do
|
140
|
+
lambda { Smoke[:feed_preperation_call_order].abstract(:value) }.should_not raise_error(NoMethodError)
|
141
|
+
Smoke[:feed_preperation_call_order].abstract.should == :value
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should chain the source when setting a property" do
|
145
|
+
Smoke[:feed_preperation_call_order].abstract(:value).should be_an_instance_of(Smoke::Source::Data)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "after setting variables" do
|
150
|
+
it "should output successfully" do
|
151
|
+
lambda { Smoke[:feed_preperation_call_order].username("benschwarz").output }.should_not raise_error
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should have used the correct url" do
|
155
|
+
Smoke[:feed_preperation_call_order].request.uri.should == @url
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
104
159
|
end
|
105
160
|
end
|
@@ -19,7 +19,7 @@ describe "YQL" do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should have been activated" do
|
22
|
-
Smoke[:search].should(be_an_instance_of(Smoke::Source::YQL
|
22
|
+
Smoke[:search].should(be_an_instance_of(Smoke::Source::YQL))
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should be a list of things" do
|
@@ -31,8 +31,18 @@ describe "YQL" do
|
|
31
31
|
Smoke[:search].output
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
describe "url" do
|
35
|
+
it "should contain the base uri for yql" do
|
36
|
+
Smoke[:search].request.uri.should =~ /^http:\/\/query.yahooapis.com\/v1\/public\/yql?/
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be format=json" do
|
40
|
+
Smoke[:search].request.uri.should include("format=json")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should contain the query" do
|
44
|
+
Smoke[:search].request.uri.should include("SELECT%20*%20FROM%20search.web%20WHERE%20query%20=%20'ruby'")
|
45
|
+
end
|
36
46
|
end
|
37
47
|
|
38
48
|
it "should have renamed url to link" do
|
data/spec/smoke_spec.rb
CHANGED
@@ -7,20 +7,6 @@ describe Smoke do
|
|
7
7
|
@source_c = TestSource.source :c
|
8
8
|
end
|
9
9
|
|
10
|
-
describe "registration" do
|
11
|
-
before do
|
12
|
-
Smoke.register(Smoke::SecretSauce) # defined in supports/mayo.rb
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should allow sources to register themselves" do
|
16
|
-
Smoke.included_modules.should include(SecretSauce)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should have an instance method of 'mayo'" do
|
20
|
-
Smoke.instance_methods.should include("mayo")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
10
|
describe "joining" do
|
25
11
|
before do
|
26
12
|
@joined = Smoke.join(:a, :b)
|
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.
|
4
|
+
version: 0.3.4
|
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-
|
12
|
+
date: 2009-06-08 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -47,7 +47,6 @@ files:
|
|
47
47
|
- lib/core_ext
|
48
48
|
- lib/core_ext/hash.rb
|
49
49
|
- lib/smoke
|
50
|
-
- lib/smoke/delayed_block.rb
|
51
50
|
- lib/smoke/origin.rb
|
52
51
|
- lib/smoke/request.rb
|
53
52
|
- lib/smoke/source
|