light-service 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +34 -0
- data/.travis.yml +16 -2
- data/Appraisals +7 -0
- data/Gemfile +2 -0
- data/README.md +126 -16
- data/RELEASES.md +4 -0
- data/Rakefile +3 -0
- data/gemfiles/activesupport_3.gemfile +8 -0
- data/gemfiles/activesupport_3.gemfile.lock +63 -0
- data/gemfiles/activesupport_4.gemfile +8 -0
- data/gemfiles/activesupport_4.gemfile.lock +71 -0
- data/lib/light-service.rb +1 -1
- data/lib/light-service/action.rb +6 -8
- data/lib/light-service/configuration.rb +0 -2
- data/lib/light-service/context.rb +32 -22
- data/lib/light-service/context/key_verifier.rb +87 -83
- data/lib/light-service/localization_adapter.rb +10 -7
- data/lib/light-service/organizer.rb +6 -3
- data/lib/light-service/organizer/with_reducer.rb +53 -39
- data/lib/light-service/organizer/with_reducer_factory.rb +3 -4
- data/lib/light-service/organizer/with_reducer_log_decorator.rb +81 -51
- data/lib/light-service/version.rb +2 -1
- data/light-service.gemspec +4 -4
- data/resources/fail_actions.png +0 -0
- data/resources/skip_actions.png +0 -0
- data/spec/acceptance/around_each_spec.rb +27 -0
- data/spec/acceptance/include_warning_spec.rb +6 -2
- data/spec/acceptance/log_from_organizer_spec.rb +39 -18
- data/spec/acceptance/message_localization_spec.rb +23 -23
- data/spec/acceptance/rollback_spec.rb +1 -3
- data/spec/action_expected_keys_spec.rb +32 -19
- data/spec/action_promised_keys_spec.rb +72 -54
- data/spec/action_spec.rb +23 -5
- data/spec/context_spec.rb +21 -17
- data/spec/localization_adapter_spec.rb +14 -10
- data/spec/organizer/with_reducer_spec.rb +19 -2
- data/spec/organizer_key_aliases_spec.rb +6 -5
- data/spec/organizer_spec.rb +32 -56
- data/spec/sample/calculates_tax_spec.rb +17 -9
- data/spec/sample/provides_free_shipping_action_spec.rb +3 -7
- data/spec/sample/tax/calculates_order_tax_action.rb +3 -2
- data/spec/sample/tax/calculates_tax.rb +3 -4
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +10 -8
- data/spec/sample/tax/provides_free_shipping_action.rb +2 -4
- data/spec/spec_helper.rb +0 -1
- data/spec/test_doubles.rb +38 -15
- metadata +38 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25a715c986fab5133c64ef50160f93524bfdcca2
|
4
|
+
data.tar.gz: 1034f64ec7c50288024a15cce41b29082983941a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1781b4242bb655bf55e257d65f97a4e4d6bf2d7eb0899bbfc509e10f62fce25d594de73bdcf426490052e3ca54a764c5ae1da049d107693c5a23d69dbe704867
|
7
|
+
data.tar.gz: 4009c8844215156df49a668a6c953cb60ae577438d35fb3452309fb005084d64b24317de65f4544a4a93af3ebc058edf9174adbbed58c5f227b791d99577bf5c
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'lib/light-service.rb'
|
4
|
+
- 'vendor/bundle/**/*'
|
5
|
+
- 'gemfiles/vendor/bundle/**/*'
|
6
|
+
- 'bin/*'
|
7
|
+
- 'light-service.gemspec'
|
8
|
+
|
9
|
+
Documentation:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Style/Encoding:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Style/StringLiterals:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Style/TrailingBlankLines:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/RedundantReturn:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/HashSyntax:
|
25
|
+
EnforcedStyle: hash_rockets
|
26
|
+
|
27
|
+
Style/PredicateName:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/TrivialAccessors:
|
31
|
+
AllowPredicates: true
|
32
|
+
|
33
|
+
Metrics/MethodLength:
|
34
|
+
Max: 15
|
data/.travis.yml
CHANGED
@@ -1,7 +1,21 @@
|
|
1
1
|
language: ruby
|
2
|
+
|
2
3
|
rvm:
|
3
|
-
- 1.9.3
|
4
4
|
- 2.0.0
|
5
5
|
- 2.1.2
|
6
|
+
- 2.2.0
|
7
|
+
- 2.3.0
|
8
|
+
|
9
|
+
before_install:
|
10
|
+
- 'echo ''gem: --no-ri --no-rdoc'' > ~/.gemrc'
|
11
|
+
- gem install bundler
|
12
|
+
- bundle install --path vendor/bundle
|
13
|
+
|
6
14
|
# uncomment this line if your project needs to run something other than `rake`:
|
7
|
-
script:
|
15
|
+
script:
|
16
|
+
- bundle exec rspec spec
|
17
|
+
- bundle exec rubocop
|
18
|
+
|
19
|
+
gemfile:
|
20
|
+
- gemfiles/activesupport_3.gemfile
|
21
|
+
- gemfiles/activesupport_4.gemfileset
|
data/Appraisals
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
![LightService](
|
1
|
+
![LightService](resources/light-service.png)
|
2
2
|
|
3
3
|
[![Gem Version](https://img.shields.io/gem/v/light-service.svg)](https://rubygems.org/gems/light-service)
|
4
4
|
[![Build Status](https://secure.travis-ci.org/adomokos/light-service.png)](http://travis-ci.org/adomokos/light-service)
|
@@ -62,7 +62,7 @@ and executes them one-by-one. Then you need to create the actions which will onl
|
|
62
62
|
|
63
63
|
This is how the organizer and actions interact with eachother:
|
64
64
|
|
65
|
-
![LightService](
|
65
|
+
![LightService](resources/organizer_and_actions.png)
|
66
66
|
|
67
67
|
```ruby
|
68
68
|
class CalculatesTax
|
@@ -146,6 +146,124 @@ end
|
|
146
146
|
I gave a [talk at RailsConf 2013](http://www.adomokos.com/2013/06/simple-and-elegant-rails-code-with.html) on
|
147
147
|
simple and elegant Rails code where I told the story of how LightService was extracted from the projects I had worked on.
|
148
148
|
|
149
|
+
|
150
|
+
## Table of Content
|
151
|
+
* [Stopping the Series of Actions](#stopping-the-series-of-actions)
|
152
|
+
* [Failing the Context](#failing-the-context)
|
153
|
+
* [Skipping the Rest of the Actions](#skipping-the-rest-of-the-actions)
|
154
|
+
* [Benchmarking Actions with Around Advice](#benchmarking-actions-with-around-advice)
|
155
|
+
* [Key Aliases](#key-aliases)
|
156
|
+
* [Logging](#logging)
|
157
|
+
* [Error Codes](#error-codes)
|
158
|
+
* [Action Rollback](#action-rollback)
|
159
|
+
* [Localizing Messages](#localizing-messages)
|
160
|
+
|
161
|
+
## Stopping the Series of Actions
|
162
|
+
When nothing unexpected happens during the organizer's call, the returned `context` will be successful. Here is how you can check for this:
|
163
|
+
```ruby
|
164
|
+
class SomeController < ApplicationController
|
165
|
+
def index
|
166
|
+
result_context = SomeOrganizer.call(current_user.id)
|
167
|
+
|
168
|
+
if result_context.success?
|
169
|
+
redirect_to foo_path, :notice => "Everything went OK! Thanks!"
|
170
|
+
else
|
171
|
+
flash[:error] = result_context.message
|
172
|
+
render :action => "new"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
However, sometimes not everything will play out as you expect it. An external API call might not be available or some complex business logic will need to stop the processing of the Series of Actions.
|
178
|
+
You have two options to stop the call chain:
|
179
|
+
|
180
|
+
1. Failing the context
|
181
|
+
2. Skipping the rest of the actions
|
182
|
+
|
183
|
+
### Failing the Context
|
184
|
+
When something goes wrong in an action and you want to halt the chain, you need to call `fail!` on the context object. This will push the context in a failure state (`context.failure? # will evalute to true`).
|
185
|
+
The context's `fail!` method can take an optional message argument, this message might help describing what went wrong.
|
186
|
+
In case you need to return immediately from the point of failure, you have to do that by calling `next context`.
|
187
|
+
|
188
|
+
Here is an example:
|
189
|
+
```ruby
|
190
|
+
class SubmitsOrderAction
|
191
|
+
extend LightService::Action
|
192
|
+
expects :order, :mailer
|
193
|
+
|
194
|
+
executed do |context|
|
195
|
+
unless context.order.submit_order_succeful?
|
196
|
+
context.fail!("Failed to submit the order")
|
197
|
+
next context
|
198
|
+
end
|
199
|
+
|
200
|
+
context.mailer.send_order_notification!
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
![LightService](resources/fail_actions.png)
|
205
|
+
|
206
|
+
In the example above the organizer called 4 actions. The first 2 actions got executed successfully. The 3rd had a failure, that pushed the context into a failure state and the 4th action was skipped.
|
207
|
+
|
208
|
+
### Skipping the rest of the actions
|
209
|
+
You can skip the rest of the actions by calling `context.skip_all!`. This behaves very similarly to the above-mentioned `fail!` mechanism, except this will not push the context into a failure state.
|
210
|
+
A good use case for this is executing the first couple of action and based on a check you might not need to execute the rest.
|
211
|
+
Here is an example of how you do it:
|
212
|
+
```ruby
|
213
|
+
class ChecksOrderStatusAction
|
214
|
+
extend LightService::Action
|
215
|
+
expects :order
|
216
|
+
|
217
|
+
executed do |context|
|
218
|
+
if context.order.send_notification?
|
219
|
+
context.skip_all!("Everything is good, no need to execute the rest of the actions")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
```
|
224
|
+
![LightService](resources/skip_actions.png)
|
225
|
+
|
226
|
+
In the example above the organizer called 4 actions. The first 2 actions got executed successfully. The 3rd decided to skip the rest, the 4th action was not invoked. The context was successful.
|
227
|
+
|
228
|
+
|
229
|
+
## Benchmarking Actions with Around Advice
|
230
|
+
Benchmarking your action is needed when you profile the series of actions. You could add benchmarking logic to each and every action, however, that would blur the business logic you have in your actions.
|
231
|
+
|
232
|
+
Take advantage of the organizer's `around_each` method, which wraps the action calls as its reducing them in order.
|
233
|
+
|
234
|
+
Check out this example:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
class LogDuration
|
238
|
+
def self.call(action, context)
|
239
|
+
start_time = Time.now
|
240
|
+
result = yield
|
241
|
+
duration = Time.now - start_time
|
242
|
+
LightService::Configuration.logger.info(
|
243
|
+
:action => action,
|
244
|
+
:duration => duration
|
245
|
+
)
|
246
|
+
|
247
|
+
result
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class CalculatesTax
|
252
|
+
extend LightService::Organizer
|
253
|
+
|
254
|
+
def self.for_order(order)
|
255
|
+
with(:order => order).around_each(LogDuration).reduce(
|
256
|
+
LooksUpTaxPercentageAction,
|
257
|
+
CalculatesOrderTaxAction,
|
258
|
+
ProvidesFreeShippingAction
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
```
|
263
|
+
|
264
|
+
Any object passed into `around_each` must respond to #call with two arguments: the action name and the context it will execute with. It is also passed a block, where LightService's action execution will be done in, so the result must be returned. While this is a little work, it also gives you before and after state access to the data for any auditing and/or checks you may need to accomplish.
|
265
|
+
|
266
|
+
|
149
267
|
## Expects and Promises
|
150
268
|
The `expects` and `promises` macros are rules for the inputs/outputs of an action.
|
151
269
|
`expects` describes what keys it needs to execute, and `promises` makes sure the keys are in the context after the
|
@@ -201,9 +319,9 @@ end
|
|
201
319
|
Take a look at [this spec](spec/action_expects_and_promises_spec.rb) to see the refactoring in action.
|
202
320
|
|
203
321
|
## Key Aliases
|
204
|
-
The `aliases` macro sets up pairs of keys and aliases in an
|
322
|
+
The `aliases` macro sets up pairs of keys and aliases in an organizer. Actions can access the context using the aliases.
|
205
323
|
|
206
|
-
This allows you to put together existing
|
324
|
+
This allows you to put together existing actions from different sources and have them work together without having to modify their code. Aliases will work with or without action `expects`.
|
207
325
|
|
208
326
|
Say for example you have actions `AnAction` and `AnotherAction` that you've used in previous projects. `AnAction` provides `:my_key` but `AnotherAction` needs to use that value but expects `:key_alias`. You can use them together in an organizer like so:
|
209
327
|
|
@@ -241,7 +359,6 @@ end
|
|
241
359
|
```
|
242
360
|
|
243
361
|
## Logging
|
244
|
-
|
245
362
|
Enable LightService's logging to better understand what goes on within the series of actions,
|
246
363
|
what's in the context or when an action fails.
|
247
364
|
|
@@ -300,7 +417,6 @@ I, [DATE] INFO -- : [LightService] - context message: Can't make a latte with a
|
|
300
417
|
```
|
301
418
|
|
302
419
|
## Error Codes
|
303
|
-
|
304
420
|
You can add some more structure to your error handling by taking advantage of error codes in the context.
|
305
421
|
Normally, when something goes wrong in your actions, you fail the process by setting the context to failure:
|
306
422
|
|
@@ -337,7 +453,6 @@ end
|
|
337
453
|
```
|
338
454
|
|
339
455
|
## Action Rollback
|
340
|
-
|
341
456
|
Sometimes your action has to undo what it did when an error occurs. Think about a chain of actions where you need
|
342
457
|
to persist records in your data store in one action and you have to call an external service in the next. What happens if there
|
343
458
|
is an error when you call the external service? You want to remove the records you previously saved. You can do it now with
|
@@ -380,7 +495,6 @@ The actions are rolled back in reversed order from the point of failure starting
|
|
380
495
|
See [this](spec/acceptance/rollback_spec.rb) acceptance test to learn more about this functionality.
|
381
496
|
|
382
497
|
## Localizing Messages
|
383
|
-
|
384
498
|
By default LightService provides a mechanism for easily translating your error or success messages via I18n. You can also provide your own custom localization adapter if your application's logic is more complex than what is shown here.
|
385
499
|
|
386
500
|
```ruby
|
@@ -446,7 +560,7 @@ LightService::Configuration.localization_adapter = MyLocalizer.new
|
|
446
560
|
|
447
561
|
# lib/my_localizer.rb
|
448
562
|
class MyLocalizer < LightService::LocalizationAdapter
|
449
|
-
|
563
|
+
|
450
564
|
# I just want to change the default lookup path
|
451
565
|
# => "light_service.failures.payment_gateway/capture_funds"
|
452
566
|
def i18n_scope_from_class(action_class, type)
|
@@ -455,12 +569,12 @@ class MyLocalizer < LightService::LocalizationAdapter
|
|
455
569
|
end
|
456
570
|
```
|
457
571
|
|
458
|
-
|
572
|
+
To get the value of a `fail!` or `succeed!` message, simply call `#message` on the returned context.
|
459
573
|
|
460
|
-
|
574
|
+
## Requirements
|
575
|
+
This gem requires ruby 2.x
|
461
576
|
|
462
577
|
## Installation
|
463
|
-
|
464
578
|
Add this line to your application's Gemfile:
|
465
579
|
|
466
580
|
gem 'light-service'
|
@@ -474,14 +588,12 @@ Or install it yourself as:
|
|
474
588
|
$ gem install light-service
|
475
589
|
|
476
590
|
## Usage
|
477
|
-
|
478
591
|
Based on the refactoring example above, just create an organizer object that calls the
|
479
592
|
actions in order and write code for the actions. That's it.
|
480
593
|
|
481
594
|
For further examples, please visit the project's [Wiki](https://github.com/adomokos/light-service/wiki).
|
482
595
|
|
483
596
|
## Contributing
|
484
|
-
|
485
597
|
1. Fork it
|
486
598
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
487
599
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
@@ -491,9 +603,7 @@ For further examples, please visit the project's [Wiki](https://github.com/adomo
|
|
491
603
|
Huge thanks to the [contributors](https://github.com/adomokos/light-service/graphs/contributors)!
|
492
604
|
|
493
605
|
## Release Notes
|
494
|
-
|
495
606
|
Follow the release notes in this [document](https://github.com/adomokos/light-service/blob/master/RELEASES.md).
|
496
607
|
|
497
608
|
## License
|
498
|
-
|
499
609
|
LightService is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
data/RELEASES.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
A brief list of new features and changes introduced with the specified version.
|
2
2
|
|
3
|
+
### 0.6.1
|
4
|
+
* Introducing [around_each](https://github.com/adomokos/light-service/pull/79) for AOP style logging and code execution
|
5
|
+
* Introducing [Rubocop](https://github.com/adomokos/light-service/commit/39aa7ea39f69a16c2df66b213fb6d638796e25f2) to the project, forcing consistant style
|
6
|
+
|
3
7
|
### 0.6.0
|
4
8
|
* Using [extend](https://github.com/adomokos/light-service/pull/64) for using class methods in Actions and Organizers
|
5
9
|
* Setting [key aliases](https://github.com/adomokos/light-service/pull/69) for the Context from the Organizer
|
data/Rakefile
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
light-service (0.6.0)
|
5
|
+
activesupport (>= 3.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (3.2.22)
|
11
|
+
i18n (~> 0.6, >= 0.6.4)
|
12
|
+
multi_json (~> 1.0)
|
13
|
+
appraisal (2.0.2)
|
14
|
+
bundler
|
15
|
+
rake
|
16
|
+
thor (>= 0.14.0)
|
17
|
+
coderay (1.0.9)
|
18
|
+
diff-lcs (1.2.5)
|
19
|
+
i18n (0.7.0)
|
20
|
+
method_source (0.8.2)
|
21
|
+
multi_json (1.11.2)
|
22
|
+
pry (0.9.12.2)
|
23
|
+
coderay (~> 1.0.5)
|
24
|
+
method_source (~> 0.8)
|
25
|
+
slop (~> 3.4)
|
26
|
+
rake (10.4.2)
|
27
|
+
rspec (3.3.0)
|
28
|
+
rspec-core (~> 3.3.0)
|
29
|
+
rspec-expectations (~> 3.3.0)
|
30
|
+
rspec-mocks (~> 3.3.0)
|
31
|
+
rspec-core (3.3.2)
|
32
|
+
rspec-support (~> 3.3.0)
|
33
|
+
rspec-expectations (3.3.1)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.3.0)
|
36
|
+
rspec-its (1.2.0)
|
37
|
+
rspec-core (>= 3.0.0)
|
38
|
+
rspec-expectations (>= 3.0.0)
|
39
|
+
rspec-mocks (3.3.2)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.3.0)
|
42
|
+
rspec-support (3.3.0)
|
43
|
+
simplecov (0.7.1)
|
44
|
+
multi_json (~> 1.0)
|
45
|
+
simplecov-html (~> 0.7.1)
|
46
|
+
simplecov-html (0.7.1)
|
47
|
+
slop (3.6.0)
|
48
|
+
thor (0.19.1)
|
49
|
+
|
50
|
+
PLATFORMS
|
51
|
+
ruby
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
activesupport (~> 3.0)
|
55
|
+
appraisal (~> 2.0)
|
56
|
+
light-service!
|
57
|
+
pry (= 0.9.12.2)
|
58
|
+
rspec (~> 3.0)
|
59
|
+
rspec-its (~> 1.0)
|
60
|
+
simplecov (~> 0.7.1)
|
61
|
+
|
62
|
+
BUNDLED WITH
|
63
|
+
1.10.6
|
@@ -0,0 +1,71 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
light-service (0.6.0)
|
5
|
+
activesupport (>= 3.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (4.2.3)
|
11
|
+
i18n (~> 0.7)
|
12
|
+
json (~> 1.7, >= 1.7.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
15
|
+
tzinfo (~> 1.1)
|
16
|
+
appraisal (2.0.2)
|
17
|
+
bundler
|
18
|
+
rake
|
19
|
+
thor (>= 0.14.0)
|
20
|
+
coderay (1.0.9)
|
21
|
+
diff-lcs (1.2.5)
|
22
|
+
i18n (0.7.0)
|
23
|
+
json (1.8.3)
|
24
|
+
method_source (0.8.2)
|
25
|
+
minitest (5.7.0)
|
26
|
+
multi_json (1.11.2)
|
27
|
+
pry (0.9.12.2)
|
28
|
+
coderay (~> 1.0.5)
|
29
|
+
method_source (~> 0.8)
|
30
|
+
slop (~> 3.4)
|
31
|
+
rake (10.4.2)
|
32
|
+
rspec (3.3.0)
|
33
|
+
rspec-core (~> 3.3.0)
|
34
|
+
rspec-expectations (~> 3.3.0)
|
35
|
+
rspec-mocks (~> 3.3.0)
|
36
|
+
rspec-core (3.3.2)
|
37
|
+
rspec-support (~> 3.3.0)
|
38
|
+
rspec-expectations (3.3.1)
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
+
rspec-support (~> 3.3.0)
|
41
|
+
rspec-its (1.2.0)
|
42
|
+
rspec-core (>= 3.0.0)
|
43
|
+
rspec-expectations (>= 3.0.0)
|
44
|
+
rspec-mocks (3.3.2)
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
+
rspec-support (~> 3.3.0)
|
47
|
+
rspec-support (3.3.0)
|
48
|
+
simplecov (0.7.1)
|
49
|
+
multi_json (~> 1.0)
|
50
|
+
simplecov-html (~> 0.7.1)
|
51
|
+
simplecov-html (0.7.1)
|
52
|
+
slop (3.6.0)
|
53
|
+
thor (0.19.1)
|
54
|
+
thread_safe (0.3.5)
|
55
|
+
tzinfo (1.2.2)
|
56
|
+
thread_safe (~> 0.1)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
ruby
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
activesupport (~> 4.0)
|
63
|
+
appraisal (~> 2.0)
|
64
|
+
light-service!
|
65
|
+
pry (= 0.9.12.2)
|
66
|
+
rspec (~> 3.0)
|
67
|
+
rspec-its (~> 1.0)
|
68
|
+
simplecov (~> 0.7.1)
|
69
|
+
|
70
|
+
BUNDLED WITH
|
71
|
+
1.10.6
|