lapse 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -19,4 +19,9 @@ group :test do
19
19
  gem 'mocha', :require => 'mocha/setup'
20
20
  gem 'simplecov', :require => false
21
21
  gem 'hashie' #unknown why this is required for certain dev envs to work (ahem, adam)
22
+ gem 'm'
23
+ gem 'thor'
24
+ gem 'faraday'
25
+ gem 'faraday_middleware'
26
+ gem 'addressable'
22
27
  end
data/Readme.markdown CHANGED
@@ -41,24 +41,11 @@ end
41
41
 
42
42
  A client takes an optional access token when you initialize it. If you don't provide one, you can still use it to make unauthenticated requests. If you do provide one, it will set the authorization header for all requests.
43
43
 
44
- ``` ruby
45
- > client = Lapse::Client.new(access_token: 'your_access_token')
46
- > current_user = client.me
47
- > current_user.username
48
- #=> "soffes"
49
- > decision = client.decision(5, 3276)
50
- #=> "Which lamp for the new apartment?"
51
- > slug = client.slug('d/3I0n0g')
52
- > slug.decision.user.username
53
- #=> "soffes"
54
- ```
55
44
 
56
45
  ## Supported Ruby Versions
57
46
 
58
47
  Lapse is tested under 1.8.7, 1.9.2, 1.9.3, 2.0.0, JRuby 1.7.2 (1.9 mode), and Rubinius 2.0.0 (1.9 mode).
59
48
 
60
- [![Build Status](https://travis-ci.org/seesawco/Lapse-rb.png?branch=master)](https://travis-ci.org/seesawco/Lapse-rb)
61
-
62
49
  ## Contributing
63
50
 
64
51
  See the [contributing guide](Contributing.markdown).
data/bin/lapse ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'lapse'
6
+ require 'lapse/cli'
7
+
8
+ Lapse::Cli.start(ARGV)
data/lapse.gemspec CHANGED
@@ -20,5 +20,5 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.required_ruby_version = '>= 1.8.7'
22
22
  gem.add_dependency 'multi_json', '~> 1.6'
23
- gem.add_dependency 'hashie', '~> 1.2.0'
23
+ gem.add_dependency 'hashie'
24
24
  end
data/lib/lapse/cli.rb ADDED
@@ -0,0 +1,206 @@
1
+ require 'thor'
2
+ require 'faraday'
3
+ require 'faraday_middleware'
4
+ require 'addressable/uri'
5
+ require 'yaml'
6
+
7
+ module Lapse
8
+ class Cli < Thor
9
+ desc 'signin', 'Signs the user in by passing in a twitter token'
10
+ def signin(host, token)
11
+ result = unauthenticated_client(host).authenticate(token)
12
+
13
+ self.auth_data = {
14
+ :access_token => result['access_token'],
15
+ :api_host => host
16
+ }
17
+
18
+ result = ["Signed in as #{result.user.username}"]
19
+ result << " on #{host}" if host
20
+ puts result.join('')
21
+ end
22
+
23
+ desc 'signout', 'Signs the user out'
24
+ def signout
25
+ File.delete config_file
26
+ puts 'Signed out'
27
+ end
28
+
29
+ desc 'create_clip', 'Creates a clip'
30
+ def create_clip(title, *image_paths)
31
+ clip = authenticated_client.create_clip
32
+ puts "Created clip id #{clip.id}"
33
+
34
+ frames = image_paths.map do |image_path|
35
+ upload_frame(clip.id, image_path)
36
+ end
37
+
38
+ authenticated_client.accept_frames(clip.id, frames.map(&:id))
39
+
40
+ puts 'Publishing clip'
41
+ authenticated_client.publish_clip(clip.id, title)
42
+
43
+ puts "#{api_host}/#{clip.slug}"
44
+ end
45
+
46
+ desc 'add_frame', 'Adds a frame to an existing clip'
47
+ option :url
48
+ method_option :open, :aliases => "-o", desc: "Open the clip"
49
+ def add_frame(clip_id)
50
+ file = get_frame(options[:url])
51
+ frame = upload_frame clip_id, file.path
52
+ clip = authenticated_client.accept_frames(clip_id, [frame.id])
53
+
54
+ url = "#{api_host}/#{clip.slug}"
55
+ if options[:open]
56
+ system "open #{url}"
57
+ else
58
+ system "echo #{url} | pbcopy"
59
+ end
60
+ end
61
+
62
+ desc 'photobooth', 'Runs a photobooth'
63
+ option :url
64
+ method_option :open, :aliases => "-o", desc: "Open the clip"
65
+ def photobooth(title, frame_count = 10)
66
+ clip = authenticated_client.create_clip
67
+
68
+ unless options[:url]
69
+ puts "Install imagesnap via \`brew install imagesnap\` to use your local camera."
70
+ return
71
+ end
72
+
73
+ frames = frame_count.to_i.times.map do |i|
74
+ file = get_frame(options[:url])
75
+ upload_frame clip.id, file.path
76
+ end
77
+
78
+ authenticated_client.accept_frames(clip.id, frames.map(&:id))
79
+
80
+ authenticated_client.publish_clip(clip.id, title)
81
+
82
+ url = "#{api_host}/#{clip.slug}"
83
+
84
+ if options[:open]
85
+ system "open #{url}"
86
+ else
87
+ system "echo #{url} | pbcopy"
88
+ end
89
+
90
+ puts "\n#{url}"
91
+ end
92
+
93
+ protected
94
+
95
+ def upload_frame(clip_id, image_path)
96
+ new_frame = authenticated_client.create_frame(clip_id)
97
+ file_upload = Faraday::UploadIO.new(image_path, 'image/jpeg')
98
+ params = new_frame.upload_params.to_hash.merge({'file' => file_upload })
99
+
100
+ conn = Faraday.new do |c|
101
+ c.use Faraday::Request::Multipart
102
+ c.adapter :net_http
103
+ end
104
+ response = conn.post(new_frame.upload_url, params)
105
+
106
+ if response.status == 303
107
+ conn.head response.headers['location']
108
+ else
109
+ raise response.body
110
+ end
111
+
112
+ putc '*'
113
+
114
+ new_frame
115
+ end
116
+
117
+ def download_image(url)
118
+ uri = Addressable::URI.parse(url)
119
+
120
+ conn = Faraday.new do |c|
121
+ #c.use FaradayMiddleware::FollowRedirects, limit: 3
122
+ c.adapter :net_http
123
+ end
124
+
125
+ if uri.user
126
+ conn.basic_auth(uri.user, uri.password)
127
+ end
128
+
129
+ response = conn.get(url)
130
+ validate_response(url, response)
131
+
132
+ convert_to_tempfile(response.body)
133
+ end
134
+
135
+ def validate_response(url, response)
136
+ raise "#{url} not found" if response.status == 404
137
+ raise "#{response.status} - #{response.body}" unless (200..300).include?(response.status)
138
+ raise "#{url} has no data" unless response.body.length > 10
139
+ end
140
+
141
+ def convert_to_tempfile(data)
142
+ file = Tempfile.open(['http', '.jpg'], encoding: 'BINARY')
143
+ file.write data
144
+ file.close
145
+ file
146
+ end
147
+
148
+ def get_frame(url = nil)
149
+ if url
150
+ file = download_image(url)
151
+ else
152
+ file = Tempfile.new(['photobooth', '.jpg'], encoding: 'BINARY')
153
+ system "imagesnap #{file.path} > /dev/null"
154
+ end
155
+ end
156
+
157
+ def unauthenticated_client(host = api_host)
158
+ options = {}.merge(server_options(host))
159
+ Lapse::Client.new(options)
160
+ end
161
+
162
+ def authenticated_client(host = api_host)
163
+ options = {:access_token => access_token}.merge(server_options(host))
164
+ Lapse::Client.new(options)
165
+ end
166
+
167
+ def server_options(host)
168
+ if host
169
+ uri = Addressable::URI.parse(host)
170
+ {:api_scheme => uri.scheme, :api_host => [uri.host, uri.port].compact.join(':')}
171
+ else
172
+ {}
173
+ end
174
+ end
175
+
176
+ def access_token
177
+ auth_data[:access_token]
178
+ end
179
+
180
+ def api_host
181
+ auth_data[:api_host]
182
+ end
183
+
184
+ def auth_data
185
+ @app_token ||= begin
186
+ if File.exist?(config_file)
187
+ YAML.load(File.open(config_file).read)
188
+ else
189
+ {}
190
+ end
191
+ end
192
+ end
193
+
194
+ def auth_data=(val)
195
+ @app_token = val
196
+ File.open(config_file, 'w+') do |f|
197
+ f.write(YAML.dump(val))
198
+ end
199
+ @app_token
200
+ end
201
+
202
+ def config_file
203
+ File.expand_path('~/.lapse')
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,38 @@
1
+ module Lapse
2
+ class Client
3
+ # Client methods for working with clips
4
+ module Clips
5
+ def all_clips
6
+ get('clips').body
7
+ end
8
+
9
+ def featured_clips
10
+ get('clips/featured').body
11
+ end
12
+
13
+ def create_clip
14
+ post('clips').body
15
+ end
16
+
17
+ def accept_frames(clip_id, frame_ids)
18
+ params = {
19
+ :frame_ids => frame_ids
20
+ }
21
+ post("clips/#{clip_id}/accept_frames", params).body
22
+ end
23
+
24
+ def publish_clip(clip_id, title)
25
+ params = {
26
+ :clip => {
27
+ :title => title
28
+ }
29
+ }
30
+ post("clips/#{clip_id}/publish", params).body
31
+ end
32
+
33
+ def destroy_clip(clip_id)
34
+ boolean_from_response(:delete, "clips/#{clip_id}")
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ module Lapse
2
+ class Client
3
+ # Client methods for working with clips
4
+ module Frames
5
+ def clip_frames(clip_id)
6
+ get("clips/#{clip_id}/frames").body
7
+ end
8
+
9
+ def create_frame(clip_id)
10
+ post("clips/#{clip_id}/frames").body
11
+ end
12
+
13
+ def destroy_frame(clip_id, frame_id)
14
+ boolean_from_response(:delete, "clips/#{clip_id}/frames/#{frame_id}")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ module Lapse
2
+ class Client
3
+ # Client methods for working with clips
4
+ module Likes
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module Lapse
2
+ class Client
3
+ module UserTimelines
4
+ def user_timeline(user_id, params = {})
5
+ get("users/#{user_id}/timelines/user", params).body
6
+ end
7
+
8
+ def user_likes_timeline(user_id, params = {})
9
+ get("users/#{user_id}/timelines/liked", params).body
10
+ end
11
+
12
+ def user_contributed_timeline(user_id, params = {})
13
+ get("users/#{user_id}/timelines/contributed", params).body
14
+ end
15
+
16
+ def user_contributors_timeline(user_id, params = {})
17
+ get("users/#{user_id}/timelines/contributors", params).body
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ module Lapse
2
+ class Client
3
+ # Client methods for working with users
4
+ module Users
5
+ # Authenticates a user
6
+ #
7
+ # Requires authenticatied client.
8
+ #
9
+ # @return [Hashie::Mash]
10
+ # @see Lapse::Client
11
+ # @example
12
+ # client.me
13
+ def authenticate(twitter_access_token)
14
+ result = post('authenticate', twitter_access_token: twitter_access_token)
15
+ hash = {
16
+ :user => result.body,
17
+ :access_token => result.headers['x-access-token']
18
+ }
19
+
20
+ case @result_format
21
+ when :mashie
22
+ Hashie::Mash.new(hash)
23
+ else
24
+ hash
25
+ end
26
+ end
27
+
28
+ # Get the current user
29
+ #
30
+ # Requires authenticatied client.
31
+ #
32
+ # @return [Hashie::Mash]
33
+ # @see Totter::Client
34
+ # @example
35
+ # client.me
36
+ def me
37
+ get('me').body
38
+ end
39
+ end
40
+ end
41
+ end
data/lib/lapse/client.rb CHANGED
@@ -6,11 +6,16 @@ module Lapse
6
6
  class Client
7
7
  Dir[File.expand_path('../client/*.rb', __FILE__)].each { |f| require f }
8
8
 
9
+ include Clips
9
10
  include Configuration
11
+ include Frames
12
+ include Users
13
+ include UserTimelines
10
14
 
11
15
  attr_reader :access_token
12
16
  attr_reader :api_scheme
13
17
  attr_reader :api_host
18
+ attr_reader :api_prefix
14
19
  attr_reader :api_version
15
20
  attr_reader :transport
16
21
  attr_reader :result_format
@@ -20,6 +25,7 @@ module Lapse
20
25
  :api_scheme => 'https',
21
26
  :api_host => 'everlapse.com',
22
27
  :api_version => '1',
28
+ :api_prefix => 'api',
23
29
  :result_format => :mashie,
24
30
  :transport => :http
25
31
  }
@@ -57,6 +63,7 @@ module Lapse
57
63
  @api_scheme = options[:api_scheme]
58
64
  @api_host = options[:api_host]
59
65
  @api_version = options[:api_version]
66
+ @api_prefix = options[:api_prefix]
60
67
  @client_token = options[:client_token] if options[:client_token]
61
68
  @transport = options[:transport]
62
69
  @result_format = options[:result_format]
@@ -71,7 +78,7 @@ module Lapse
71
78
  #
72
79
  # @return [String] API base URL
73
80
  def base_url
74
- "#{@api_scheme}://#{@api_host}/v#{@api_version}/"
81
+ "#{@api_scheme}://#{@api_host}/#{@api_prefix}/v#{@api_version}/"
75
82
  end
76
83
 
77
84
  # Is the client has an access token.
@@ -44,7 +44,7 @@ module Lapse
44
44
  response = http.request(request)
45
45
 
46
46
  # Check for errors
47
- handle_error(response)
47
+ handle_error(request, response)
48
48
 
49
49
  # Return the raw response object
50
50
  response
@@ -84,14 +84,14 @@ module Lapse
84
84
  end
85
85
  end
86
86
 
87
- def handle_error(response)
87
+ def handle_error(request, response)
88
88
  # Find error or return
89
89
  return unless error = Lapse::ERROR_MAP[response.code.to_i]
90
90
 
91
91
  # Try to add a useful message
92
92
  message = nil
93
93
  begin
94
- message = MultiJson.load(response.body)['error_description']
94
+ message = MultiJson.load(response.body)['error_description'] || request.path
95
95
  rescue MultiJson::DecodeError => e
96
96
  end
97
97
 
data/lib/lapse/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Lapse
2
2
  # Verion of the Lapse gem
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.3'
4
4
  end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class ClipsTest < Lapse::TestCase
4
+
5
+ def test_all_clips
6
+ stub_request(:get, 'https://everlapse.com/api/v1/clips').to_return(:status => 200, :body => "[]")
7
+ assert_equal [], authenticated_client.all_clips
8
+ end
9
+
10
+ def test_featured_clips
11
+ stub_request(:get, 'https://everlapse.com/api/v1/clips/featured').to_return(:status => 200, :body => "[]")
12
+ assert_equal [], authenticated_client.featured_clips
13
+ end
14
+
15
+ def test_create_clip
16
+ stub_request(:post, 'https://everlapse.com/api/v1/clips').to_return(:status => 200, :body => "{}")
17
+ assert_equal Hash.new, authenticated_client.create_clip
18
+ end
19
+
20
+ def test_accept_frames
21
+ stub_request(:post, 'https://everlapse.com/api/v1/clips/1/accept_frames').to_return(:status => 200, :body => "{}")
22
+ assert_equal Hash.new, authenticated_client.accept_frames(1, [1, 2, 3, 4])
23
+ end
24
+
25
+ def test_publish_clip
26
+ stub_request(:post, 'https://everlapse.com/api/v1/clips/1/publish').to_return(:status => 200, :body => "{}")
27
+ assert_equal Hash.new, authenticated_client.publish_clip(1)
28
+ end
29
+
30
+ def test_destroy_clip
31
+ stub_request(:delete, 'https://everlapse.com/api/v1/clips/1').to_return(:status => 200)
32
+ assert authenticated_client.destroy_clip(1)
33
+ end
34
+
35
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class FramesTest < Lapse::TestCase
4
+
5
+ def test_clip_frames
6
+ stub_request(:get, 'https://everlapse.com/api/v1/clips/1/frames').to_return(:status => 200, :body => "[]")
7
+ assert_equal [], authenticated_client.clip_frames(1)
8
+ end
9
+
10
+ def test_create_frame
11
+ stub_request(:post, 'https://everlapse.com/api/v1/clips/1/frames').to_return(:status => 200, :body => "{}")
12
+ assert_equal Hash.new, authenticated_client.create_frame(1)
13
+ end
14
+
15
+ def test_destroy_frame
16
+ stub_request(:delete, 'https://everlapse.com/api/v1/clips/1/frames/2').to_return(:status => 200)
17
+ assert authenticated_client.destroy_frame(1, 2)
18
+ end
19
+
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class UsersTest < Lapse::TestCase
4
+ def test_authenticate
5
+ key = 'test_key'
6
+
7
+ stub_request(:post, 'https://everlapse.com/api/v1/authenticate').with(:body => "{\"twitter_access_token\":\"#{key}\"}").
8
+ to_return(:status => 200, :body => "{}", :headers => {"x-access-token" => 'fake_token'})
9
+
10
+ result = unauthenticated_client.authenticate(key)
11
+ assert_equal Hash.new, result.user
12
+ assert_equal 'fake_token', result.access_token
13
+ end
14
+
15
+ def test_me
16
+ stub_request(:get, 'https://everlapse.com/api/v1/me').to_return(:status => 200, :body => "{}")
17
+ assert_equal Hash.new, authenticated_client.me
18
+ end
19
+ end
@@ -15,16 +15,19 @@ class ClientTest < Lapse::TestCase
15
15
 
16
16
  def test_base_url
17
17
  client = Lapse::Client.new
18
- assert_equal 'https://everlapse.com/v1/', client.base_url
18
+ assert_equal 'https://everlapse.com/api/v1/', client.base_url
19
19
 
20
20
  client = Lapse::Client.new(:api_scheme => 'http', :api_host => 'example.com', :api_version => 42)
21
- assert_equal 'http://example.com/v42/', client.base_url
21
+ assert_equal 'http://example.com/api/v42/', client.base_url
22
22
 
23
23
  client = Lapse::Client.new(:api_url => 'http://example.com')
24
- assert_equal 'http://example.com/v1/', client.base_url
24
+ assert_equal 'http://example.com/api/v1/', client.base_url
25
25
 
26
26
  client = Lapse::Client.new(:api_url => 'http://localhost:3000')
27
- assert_equal 'http://localhost:3000/v1/', client.base_url
27
+ assert_equal 'http://localhost:3000/api/v1/', client.base_url
28
+
29
+ client = Lapse::Client.new(:api_prefix => 'asd')
30
+ assert_equal 'https://everlapse.com/asd/v1/', client.base_url
28
31
  end
29
32
 
30
33
  def test_ssl?
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class HttpTest < Lapse::TestCase
4
4
  def test_default_mashie_format
5
- stub_request(:get, 'https://everlapse.com/v1/configuration').to_return(status: 200, body: "{}")
5
+ stub_request(:get, 'https://everlapse.com/api/v1/configuration').to_return(:status => 200, :body => "{}")
6
6
  assert_equal Hashie::Mash, Lapse.configuration.class
7
7
  end
8
8
  end
@@ -1,9 +1,9 @@
1
1
  module ClientMacros
2
- def local_client
3
- client = Lapse::Client.new(:access_token => '9774e653f7b3c1de5f21b61adc08ba24', :api_host => 'localhost:5000', :api_scheme => 'http')
2
+ def authenticated_client
3
+ Lapse::Client.new(:access_token => 'access_token')
4
4
  end
5
5
 
6
- def unauthenticated_monkeybars_production_client
7
- Lapse::Client.new(:client_token => '29756b7591819c57e01ac2c6d9ae5311')
6
+ def unauthenticated_client
7
+ Lapse::Client.new
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lapse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-06-05 00:00:00.000000000 Z
14
+ date: 2013-06-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: multi_json
@@ -34,23 +34,24 @@ dependencies:
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  none: false
36
36
  requirements:
37
- - - ~>
37
+ - - ! '>='
38
38
  - !ruby/object:Gem::Version
39
- version: 1.2.0
39
+ version: '0'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  none: false
44
44
  requirements:
45
- - - ~>
45
+ - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
- version: 1.2.0
47
+ version: '0'
48
48
  description: Ruby gem for working with the Everlapse API.
49
49
  email:
50
50
  - sam@soff.es
51
51
  - gotwalt@gmail.com
52
52
  - adam.g.ryan@gmail.com
53
- executables: []
53
+ executables:
54
+ - lapse
54
55
  extensions: []
55
56
  extra_rdoc_files: []
56
57
  files:
@@ -61,15 +62,25 @@ files:
61
62
  - LICENSE
62
63
  - Rakefile
63
64
  - Readme.markdown
65
+ - bin/lapse
64
66
  - lapse.gemspec
65
67
  - lib/lapse.rb
68
+ - lib/lapse/cli.rb
66
69
  - lib/lapse/client.rb
70
+ - lib/lapse/client/clips.rb
67
71
  - lib/lapse/client/configuration.rb
72
+ - lib/lapse/client/frames.rb
73
+ - lib/lapse/client/likes.rb
74
+ - lib/lapse/client/user_timelines.rb
75
+ - lib/lapse/client/users.rb
68
76
  - lib/lapse/error.rb
69
77
  - lib/lapse/response.rb
70
78
  - lib/lapse/transport.rb
71
79
  - lib/lapse/transport/http.rb
72
80
  - lib/lapse/version.rb
81
+ - test/lapse/client/clips_test.rb
82
+ - test/lapse/client/frames_test.rb
83
+ - test/lapse/client/users_test.rb
73
84
  - test/lapse/client_test.rb
74
85
  - test/lapse/transport/http_test.rb
75
86
  - test/lapse_test.rb
@@ -96,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
107
  version: '0'
97
108
  segments:
98
109
  - 0
99
- hash: -3688395446889741402
110
+ hash: -4262868761146380689
100
111
  requirements: []
101
112
  rubyforge_project:
102
113
  rubygems_version: 1.8.23
@@ -104,6 +115,9 @@ signing_key:
104
115
  specification_version: 3
105
116
  summary: Ruby gem for working with the Everlapse API.
106
117
  test_files:
118
+ - test/lapse/client/clips_test.rb
119
+ - test/lapse/client/frames_test.rb
120
+ - test/lapse/client/users_test.rb
107
121
  - test/lapse/client_test.rb
108
122
  - test/lapse/transport/http_test.rb
109
123
  - test/lapse_test.rb