hutch 0.19.0-java
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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +438 -0
- data/Gemfile +22 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +317 -0
- data/Rakefile +14 -0
- data/bin/hutch +8 -0
- data/circle.yml +3 -0
- data/examples/consumer.rb +13 -0
- data/examples/producer.rb +10 -0
- data/hutch.gemspec +30 -0
- data/lib/hutch.rb +62 -0
- data/lib/hutch/adapter.rb +11 -0
- data/lib/hutch/adapters/bunny.rb +33 -0
- data/lib/hutch/adapters/march_hare.rb +37 -0
- data/lib/hutch/broker.rb +374 -0
- data/lib/hutch/cli.rb +205 -0
- data/lib/hutch/config.rb +125 -0
- data/lib/hutch/consumer.rb +75 -0
- data/lib/hutch/error_handlers.rb +8 -0
- data/lib/hutch/error_handlers/airbrake.rb +26 -0
- data/lib/hutch/error_handlers/honeybadger.rb +28 -0
- data/lib/hutch/error_handlers/logger.rb +16 -0
- data/lib/hutch/error_handlers/sentry.rb +23 -0
- data/lib/hutch/exceptions.rb +7 -0
- data/lib/hutch/logging.rb +32 -0
- data/lib/hutch/message.rb +31 -0
- data/lib/hutch/serializers/identity.rb +19 -0
- data/lib/hutch/serializers/json.rb +22 -0
- data/lib/hutch/tracers.rb +6 -0
- data/lib/hutch/tracers/newrelic.rb +19 -0
- data/lib/hutch/tracers/null_tracer.rb +15 -0
- data/lib/hutch/version.rb +4 -0
- data/lib/hutch/worker.rb +143 -0
- data/spec/hutch/broker_spec.rb +377 -0
- data/spec/hutch/cli_spec.rb +80 -0
- data/spec/hutch/config_spec.rb +126 -0
- data/spec/hutch/consumer_spec.rb +130 -0
- data/spec/hutch/error_handlers/airbrake_spec.rb +34 -0
- data/spec/hutch/error_handlers/honeybadger_spec.rb +36 -0
- data/spec/hutch/error_handlers/logger_spec.rb +15 -0
- data/spec/hutch/error_handlers/sentry_spec.rb +20 -0
- data/spec/hutch/logger_spec.rb +28 -0
- data/spec/hutch/message_spec.rb +38 -0
- data/spec/hutch/serializers/json_spec.rb +17 -0
- data/spec/hutch/worker_spec.rb +99 -0
- data/spec/hutch_spec.rb +87 -0
- data/spec/spec_helper.rb +40 -0
- metadata +194 -0
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem "rake"
|
7
|
+
gem "guard", "~> 0.8.8"
|
8
|
+
gem "guard-rspec", "~> 0.5.4"
|
9
|
+
end
|
10
|
+
|
11
|
+
group :development, :test do
|
12
|
+
gem "sentry-raven"
|
13
|
+
gem "honeybadger"
|
14
|
+
gem "coveralls", require: false
|
15
|
+
gem "newrelic_rpm"
|
16
|
+
gem "airbrake"
|
17
|
+
end
|
18
|
+
|
19
|
+
group :development, :darwin do
|
20
|
+
gem "rb-fsevent", "~> 0.9"
|
21
|
+
gem "growl", "~> 1.0.3"
|
22
|
+
end
|
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013-2014 GoCardless
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+

|
2
|
+
|
3
|
+
Hutch is a Ruby library for enabling asynchronous inter-service communication
|
4
|
+
in a service-oriented architecture, using RabbitMQ.
|
5
|
+
|
6
|
+
[](http://badge.fury.io/rb/hutch)
|
7
|
+
[](https://travis-ci.org/gocardless/hutch)
|
8
|
+
[](https://gemnasium.com/gocardless/hutch)
|
9
|
+
[](https://codeclimate.com/github/gocardless/hutch)
|
10
|
+
|
11
|
+
To install with RubyGems:
|
12
|
+
|
13
|
+
```
|
14
|
+
$ gem install hutch
|
15
|
+
```
|
16
|
+
|
17
|
+
## Project Maturity
|
18
|
+
|
19
|
+
Hutch is a moderately mature project (started in early 2013)
|
20
|
+
that was extracted from production systems.
|
21
|
+
|
22
|
+
|
23
|
+
## Overview
|
24
|
+
|
25
|
+
Hutch is a conventions-based framework for writing services that communicate
|
26
|
+
over RabbitMQ. Hutch is opinionated: it uses topic exchanges for message
|
27
|
+
distribution and makes some assumptions about how consumers and publishers
|
28
|
+
should work.
|
29
|
+
|
30
|
+
With Hutch, consumers are stored in separate files and include the `Hutch::Consumer` module.
|
31
|
+
They are then loaded by a command line runner which connects to RabbitMQ, sets up queues and bindings,
|
32
|
+
and so on. Publishers connect to RabbitMQ via `Hutch.connect` and publish using `Hutch.publish`.
|
33
|
+
|
34
|
+
Hutch uses [Bunny](http://rubybunny.info) under the hood.
|
35
|
+
|
36
|
+
|
37
|
+
## Defining Consumers
|
38
|
+
|
39
|
+
Consumers receive messages from a RabbitMQ queue. That queue may be bound to
|
40
|
+
one or more topics (represented by routing keys).
|
41
|
+
|
42
|
+
To create a consumer, include the `Hutch::Consumer` module in a class that
|
43
|
+
defines a `#process` method. `#process` should take a single argument, which
|
44
|
+
will be a `Message` object. The `Message` object encapsulates the message data,
|
45
|
+
along with any associated metadata. To access properties of the message, use
|
46
|
+
Hash-style indexing syntax:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
message[:id] # => "02ABCXYZ"
|
50
|
+
```
|
51
|
+
|
52
|
+
To subscribe to a topic, pass a routing key to `consume` in the class
|
53
|
+
definition. To bind to multiple routing keys, simply pass extra routing keys
|
54
|
+
in as additional arguments. Refer to the [RabbitMQ docs on topic exchanges
|
55
|
+
][topic-docs] for more information about how to use routing keys. Here's an
|
56
|
+
example consumer:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class FailedPaymentConsumer
|
60
|
+
include Hutch::Consumer
|
61
|
+
consume 'gc.ps.payment.failed'
|
62
|
+
|
63
|
+
def process(message)
|
64
|
+
mark_payment_as_failed(message[:id])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
By default, the queue name will be named using the consumer class. You can set
|
70
|
+
the queue name explicitly by using the `queue_name` method:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class FailedPaymentConsumer
|
74
|
+
include Hutch::Consumer
|
75
|
+
consume 'gc.ps.payment.failed'
|
76
|
+
queue_name 'failed_payments'
|
77
|
+
|
78
|
+
def process(message)
|
79
|
+
mark_payment_as_failed(message[:id])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
You can also set custom arguments per consumer. This example declares a consumer with
|
85
|
+
a maximum length of 10 messages:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
class FailedPaymentConsumer
|
89
|
+
include Hutch::Consumer
|
90
|
+
consume 'gc.ps.payment.failed'
|
91
|
+
arguments 'x-max-length' => 10
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
Custom queue arguments can be found on [this page](https://www.rabbitmq.com/extensions.html).
|
96
|
+
|
97
|
+
Consumers can write to Hutch's log by calling the logger method. The logger method returns
|
98
|
+
a [Logger object](http://ruby-doc.org/stdlib-2.1.2/libdoc/logger/rdoc/Logger.html).
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
class FailedPaymentConsumer
|
102
|
+
include Hutch::Consumer
|
103
|
+
consume 'gc.ps.payment.failed'
|
104
|
+
|
105
|
+
def process(message)
|
106
|
+
logger.info "Marking payment #{message[:id]} as failed"
|
107
|
+
mark_payment_as_failed(message[:id])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
If you are using Hutch with Rails and want to make Hutch log to the Rails
|
113
|
+
logger rather than `stdout`, add this to `config/initializers/hutch.rb`
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
Hutch::Logging.logger = Rails.logger
|
117
|
+
```
|
118
|
+
|
119
|
+
A logger can be set for the client by adding this config before calling `Hutch.connect`
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
client_logger = Logger.new("/path/to/bunny.log")
|
123
|
+
Hutch::Config.set(:client_logger, client_logger)
|
124
|
+
```
|
125
|
+
|
126
|
+
See this [RabbitMQ tutorial on topic exchanges](http://www.rabbitmq.com/tutorials/tutorial-five-ruby.html)
|
127
|
+
to learn more.
|
128
|
+
|
129
|
+
### Message Processing Tracers
|
130
|
+
|
131
|
+
Tracers allow you to track message processing.
|
132
|
+
|
133
|
+
#### NewRelic
|
134
|
+
```ruby
|
135
|
+
Hutch::Config.set(:tracer, Hutch::Tracers::NewRelic)
|
136
|
+
```
|
137
|
+
This will enable NewRelic custom instrumentation. Batteries included! Screenshoots available [here](https://monosnap.com/list/557020a000779174f23467e3).
|
138
|
+
|
139
|
+
## Running Hutch
|
140
|
+
|
141
|
+
After installing the Hutch gem, you should be able to start it by simply
|
142
|
+
running `hutch` on the command line. `hutch` takes a number of options:
|
143
|
+
|
144
|
+
```console
|
145
|
+
$ hutch -h
|
146
|
+
usage: hutch [options]
|
147
|
+
--mq-host HOST Set the RabbitMQ host
|
148
|
+
--mq-port PORT Set the RabbitMQ port
|
149
|
+
-t, --[no-]mq-tls Use TLS for the AMQP connection
|
150
|
+
--mq-tls-cert FILE Certificate for TLS client verification
|
151
|
+
--mq-tls-key FILE Private key for TLS client verification
|
152
|
+
--mq-exchange EXCHANGE Set the RabbitMQ exchange
|
153
|
+
--mq-vhost VHOST Set the RabbitMQ vhost
|
154
|
+
--mq-username USERNAME Set the RabbitMQ username
|
155
|
+
--mq-password PASSWORD Set the RabbitMQ password
|
156
|
+
--mq-api-host HOST Set the RabbitMQ API host
|
157
|
+
--mq-api-port PORT Set the RabbitMQ API port
|
158
|
+
-s, --[no-]mq-api-ssl Use SSL for the RabbitMQ API
|
159
|
+
--config FILE Load Hutch configuration from a file
|
160
|
+
--require PATH Require a Rails app or path
|
161
|
+
--[no-]autoload-rails Require the current rails app directory
|
162
|
+
-q, --quiet Quiet logging
|
163
|
+
-v, --verbose Verbose logging
|
164
|
+
--version Print the version and exit
|
165
|
+
-h, --help Show this message and exit
|
166
|
+
```
|
167
|
+
|
168
|
+
The first three are for configuring which RabbitMQ instance to connect to.
|
169
|
+
`--require` is covered in the next section. Configurations can also be
|
170
|
+
specified in a YAML file for convenience by passing the file location
|
171
|
+
to the --config option. The file should look like:
|
172
|
+
|
173
|
+
```yaml
|
174
|
+
mq_username: peter
|
175
|
+
mq_password: rabbit
|
176
|
+
mq_host: broker.yourhost.com
|
177
|
+
```
|
178
|
+
|
179
|
+
Passing a setting as a command-line option will overwrite what's specified
|
180
|
+
in the config file, allowing for easy customization.
|
181
|
+
|
182
|
+
### Loading Consumers
|
183
|
+
|
184
|
+
Using Hutch with a Rails app is simple. Either start Hutch in the working
|
185
|
+
directory of a Rails app, or pass the path to a Rails app in with the
|
186
|
+
`--require` option. Consumers defined in Rails apps should be placed with in
|
187
|
+
the `app/consumers/` directory, to allow them to be auto-loaded when Rails
|
188
|
+
boots.
|
189
|
+
|
190
|
+
To require files that define consumers manually, simply pass each file as an
|
191
|
+
option to `--require`. Hutch will automatically detect whether you've provided
|
192
|
+
a Rails app or a standard file, and take the appropriate behaviour:
|
193
|
+
|
194
|
+
```bash
|
195
|
+
$ hutch --require path/to/rails-app # loads a rails app
|
196
|
+
$ hutch --require path/to/file.rb # loads a ruby file
|
197
|
+
```
|
198
|
+
|
199
|
+
### Stopping Hutch
|
200
|
+
|
201
|
+
Hutch supports graceful stops. That means that if done correctly, Hutch will wait for your consumer to finish processing before exiting.
|
202
|
+
|
203
|
+
To gracefully stop your workers, you may send the following signals to your Hutch processes: `INT`, `TERM`, or `QUIT`.
|
204
|
+
|
205
|
+
```bash
|
206
|
+
kill -SIGINT 123 # or kill -2 123
|
207
|
+
kill -SIGTERM 456 # or kill -15 456
|
208
|
+
kill -SIGQUIT 789 # or kill -3 789
|
209
|
+
```
|
210
|
+
|
211
|
+

|
212
|
+
|
213
|
+
## Producers
|
214
|
+
|
215
|
+
Hutch includes a `publish` method for sending messages to Hutch consumers. When
|
216
|
+
possible, this should be used, rather than directly interfacing with RabbitMQ
|
217
|
+
libraries.
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
Hutch.connect
|
221
|
+
Hutch.publish('routing.key', subject: 'payment', action: 'received')
|
222
|
+
```
|
223
|
+
|
224
|
+
### Producer Configuration
|
225
|
+
|
226
|
+
Producers are not run with the 'hutch' command. You can specify configuration
|
227
|
+
options as follows:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
Hutch::Config.set(:mq_exchange, 'name')
|
231
|
+
```
|
232
|
+
|
233
|
+
### Publisher Confirms
|
234
|
+
|
235
|
+
For maximum message reliability when producing messages, you can force Hutch to use
|
236
|
+
[Publisher Confirms](https://www.rabbitmq.com/confirms.html) and wait for a confirmation
|
237
|
+
after every message published. This is the safest possible option for publishers
|
238
|
+
but also results in a **significant throughput drop**.
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
Hutch::Config.set(:force_publisher_confirms, true)
|
242
|
+
```
|
243
|
+
|
244
|
+
### Writing Well-Behaved Publishers
|
245
|
+
|
246
|
+
You may need to send messages to Hutch from languages other than Ruby. This
|
247
|
+
prevents the use of `Hutch.publish`, requiring custom publication code to be
|
248
|
+
written. There are a few things to keep in mind when writing producers that
|
249
|
+
send messages to Hutch.
|
250
|
+
|
251
|
+
- Make sure that the producer exchange name matches the exchange name that
|
252
|
+
Hutch is using.
|
253
|
+
- Hutch works with topic exchanges, check the producer is also using topic
|
254
|
+
exchanges.
|
255
|
+
- Use message routing keys that match those used in your Hutch consumers.
|
256
|
+
- Be sure your exchanges are marked as durable. In the Ruby AMQP gem, this is
|
257
|
+
done by passing `durable: true` to the exchange creation method.
|
258
|
+
- Publish messages as persistent.
|
259
|
+
- Using publisher confirms is highly recommended.
|
260
|
+
|
261
|
+
Here's an example of a well-behaved publisher, minus publisher confirms:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
AMQP.connect(host: config[:host]) do |connection|
|
265
|
+
channel = AMQP::Channel.new(connection)
|
266
|
+
exchange = channel.topic(config[:exchange], durable: true)
|
267
|
+
|
268
|
+
message = JSON.dump({ subject: 'Test', id: 'abc' })
|
269
|
+
exchange.publish(message, routing_key: 'test', persistent: true)
|
270
|
+
end
|
271
|
+
```
|
272
|
+
|
273
|
+
If using publisher confirms with amqp gem, see [this issue][pc-issue]
|
274
|
+
and [this gist][pc-gist] for more info.
|
275
|
+
|
276
|
+
## Configuration Reference
|
277
|
+
|
278
|
+
### Config File
|
279
|
+
|
280
|
+
It is recommended to use a separate config file, unless you use URIs for connection (see below).
|
281
|
+
|
282
|
+
Known configuration parameters are:
|
283
|
+
|
284
|
+
* `mq_host`: RabbitMQ hostname (default: `localhost`)
|
285
|
+
* `mq_port`: RabbitMQ port (default: `5672`)
|
286
|
+
* `mq_vhost`: vhost to use (default: `/`)
|
287
|
+
* `mq_username`: username to use (default: `guest`, only can connect from localhost as of RabbitMQ 3.3.0)
|
288
|
+
* `mq_password`: password to use (default: `guest`)
|
289
|
+
* `mq_tls`: should TLS be used? (default: `false`)
|
290
|
+
* `mq_tls_cert`: path to client TLS certificate (public key)
|
291
|
+
* `mq_tls_key`: path to client TLS private key
|
292
|
+
* `mq_tls_ca_certificates`: array of paths to CA keys (if not specified to Hutch, will default to Bunny defaults which are system-dependent)
|
293
|
+
* `mq_verify_peer`: should SSL certificate be verified? (default: `true`)
|
294
|
+
* `require_paths`: array of paths to require
|
295
|
+
* `autoload_rails`: should Hutch command line runner try to automatically load Rails environment files?
|
296
|
+
* `daemonise`: should Hutch runner process daemonise?
|
297
|
+
* `pidfile`: path to PID file the runner should use
|
298
|
+
* `channel_prefetch`: basic.qos prefetch value to use (default: `0`, no limit). See Bunny and RabbitMQ documentation.
|
299
|
+
* `publisher_confirms`: enables publisher confirms. Leaves it up to the app how they are
|
300
|
+
tracked (e.g. using `Hutch::Broker#confirm_select` callback or `Hutch::Broker#wait_for_confirms`)
|
301
|
+
* `force_publisher_confirms`: enables publisher confirms, forces `Hutch::Broker#wait_for_confirms` for every publish. **This is the safest option which also offers the lowest throughput**.
|
302
|
+
* `log_level`: log level used by the standard Ruby logger (default: `Logger::INFO`)
|
303
|
+
* `mq_exchange`: exchange to use for publishing (default: `hutch`)
|
304
|
+
* `heartbeat`: [RabbitMQ heartbeat timeout](http://rabbitmq.com/heartbeats.html) (default: `30`)
|
305
|
+
* `connection_timeout`: Bunny's socket open timeout (default: `11`)
|
306
|
+
* `read_timeout`: Bunny's socket read timeout (default: `11`)
|
307
|
+
* `write_timemout`: Bunny's socket write timeout (default: `11`)
|
308
|
+
* `tracer`: tracer to use to track message processing
|
309
|
+
|
310
|
+
|
311
|
+
## Supported RabbitMQ Versions
|
312
|
+
|
313
|
+
Hutch requires RabbitMQ 3.3 or later.
|
314
|
+
|
315
|
+
---
|
316
|
+
|
317
|
+
GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs/backend_developer).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
desc "Run an IRB session with Hutch pre-loaded"
|
4
|
+
task :console do
|
5
|
+
exec "irb -I lib -r hutch"
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Run the test suite"
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
10
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
11
|
+
t.rspec_opts = %w(--color --format doc)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
data/bin/hutch
ADDED
data/circle.yml
ADDED
data/hutch.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path('../lib/hutch/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
if defined?(JRUBY_VERSION)
|
5
|
+
gem.platform = 'java'
|
6
|
+
gem.add_runtime_dependency 'march_hare', '>= 2.11.0'
|
7
|
+
else
|
8
|
+
gem.platform = Gem::Platform::RUBY
|
9
|
+
gem.add_runtime_dependency 'bunny', '>= 2.2.0'
|
10
|
+
end
|
11
|
+
gem.add_runtime_dependency 'carrot-top', '~> 0.0.7'
|
12
|
+
gem.add_runtime_dependency 'multi_json', '~> 1.11.2'
|
13
|
+
gem.add_runtime_dependency 'activesupport', '>= 3.0'
|
14
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
15
|
+
gem.add_development_dependency 'simplecov', '~> 0.7.1'
|
16
|
+
|
17
|
+
gem.name = 'hutch'
|
18
|
+
gem.summary = 'Easy inter-service communication using RabbitMQ.'
|
19
|
+
gem.description = 'Hutch is a Ruby library for enabling asynchronous ' +
|
20
|
+
'inter-service communication using RabbitMQ.'
|
21
|
+
gem.version = Hutch::VERSION.dup
|
22
|
+
gem.authors = ['Harry Marr']
|
23
|
+
gem.email = ['developers@gocardless.com']
|
24
|
+
gem.homepage = 'https://github.com/gocardless/hutch'
|
25
|
+
gem.require_paths = ['lib']
|
26
|
+
gem.license = 'MIT'
|
27
|
+
gem.executables = ['hutch']
|
28
|
+
gem.files = `git ls-files`.split("\n")
|
29
|
+
gem.test_files = `git ls-files -- spec/*`.split("\n")
|
30
|
+
end
|