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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +34 -0
  3. data/.travis.yml +16 -2
  4. data/Appraisals +7 -0
  5. data/Gemfile +2 -0
  6. data/README.md +126 -16
  7. data/RELEASES.md +4 -0
  8. data/Rakefile +3 -0
  9. data/gemfiles/activesupport_3.gemfile +8 -0
  10. data/gemfiles/activesupport_3.gemfile.lock +63 -0
  11. data/gemfiles/activesupport_4.gemfile +8 -0
  12. data/gemfiles/activesupport_4.gemfile.lock +71 -0
  13. data/lib/light-service.rb +1 -1
  14. data/lib/light-service/action.rb +6 -8
  15. data/lib/light-service/configuration.rb +0 -2
  16. data/lib/light-service/context.rb +32 -22
  17. data/lib/light-service/context/key_verifier.rb +87 -83
  18. data/lib/light-service/localization_adapter.rb +10 -7
  19. data/lib/light-service/organizer.rb +6 -3
  20. data/lib/light-service/organizer/with_reducer.rb +53 -39
  21. data/lib/light-service/organizer/with_reducer_factory.rb +3 -4
  22. data/lib/light-service/organizer/with_reducer_log_decorator.rb +81 -51
  23. data/lib/light-service/version.rb +2 -1
  24. data/light-service.gemspec +4 -4
  25. data/resources/fail_actions.png +0 -0
  26. data/resources/skip_actions.png +0 -0
  27. data/spec/acceptance/around_each_spec.rb +27 -0
  28. data/spec/acceptance/include_warning_spec.rb +6 -2
  29. data/spec/acceptance/log_from_organizer_spec.rb +39 -18
  30. data/spec/acceptance/message_localization_spec.rb +23 -23
  31. data/spec/acceptance/rollback_spec.rb +1 -3
  32. data/spec/action_expected_keys_spec.rb +32 -19
  33. data/spec/action_promised_keys_spec.rb +72 -54
  34. data/spec/action_spec.rb +23 -5
  35. data/spec/context_spec.rb +21 -17
  36. data/spec/localization_adapter_spec.rb +14 -10
  37. data/spec/organizer/with_reducer_spec.rb +19 -2
  38. data/spec/organizer_key_aliases_spec.rb +6 -5
  39. data/spec/organizer_spec.rb +32 -56
  40. data/spec/sample/calculates_tax_spec.rb +17 -9
  41. data/spec/sample/provides_free_shipping_action_spec.rb +3 -7
  42. data/spec/sample/tax/calculates_order_tax_action.rb +3 -2
  43. data/spec/sample/tax/calculates_tax.rb +3 -4
  44. data/spec/sample/tax/looks_up_tax_percentage_action.rb +10 -8
  45. data/spec/sample/tax/provides_free_shipping_action.rb +2 -4
  46. data/spec/spec_helper.rb +0 -1
  47. data/spec/test_doubles.rb +38 -15
  48. metadata +38 -28
@@ -1,6 +1,6 @@
1
1
  require 'logger'
2
2
 
3
- require "light-service/version"
3
+ require 'light-service/version'
4
4
 
5
5
  require 'light-service/errors'
6
6
  require 'light-service/configuration'
@@ -1,12 +1,13 @@
1
1
  module LightService
2
2
  module Action
3
-
4
3
  def self.extended(base_class)
5
4
  base_class.extend Macros
6
5
  end
7
6
 
8
7
  def self.included(base_class)
9
- ActiveSupport::Deprecation.warn "including LightService::Action is deprecated. Please use `extend LightService::Action` instead"
8
+ msg = "including LightService::Action is deprecated. " \
9
+ "Please use `extend LightService::Action` instead"
10
+ ActiveSupport::Deprecation.warn(msg)
10
11
  base_class.extend Macros
11
12
  end
12
13
 
@@ -46,22 +47,20 @@ module LightService
46
47
  end
47
48
 
48
49
  def rolled_back
49
- raise "`rolled_back` macro can not be invoked again" if self.respond_to?(:rollback)
50
+ msg = "`rolled_back` macro can not be invoked again"
51
+ fail msg if respond_to?(:rollback)
50
52
 
51
53
  define_singleton_method :rollback do |context = {}|
52
54
  yield(context)
53
55
 
54
56
  context
55
57
  end
56
-
57
58
  end
58
59
 
59
60
  private
60
61
 
61
62
  def create_action_context(context)
62
- if context.is_a? LightService::Context
63
- return context
64
- end
63
+ return context if context.is_a? LightService::Context
65
64
 
66
65
  LightService::Context.make(context)
67
66
  end
@@ -70,6 +69,5 @@ module LightService
70
69
  expected_keys + promised_keys
71
70
  end
72
71
  end
73
-
74
72
  end
75
73
  end
@@ -1,6 +1,5 @@
1
1
  module LightService
2
2
  class Configuration
3
-
4
3
  class << self
5
4
  attr_writer :logger, :localization_adapter
6
5
 
@@ -20,6 +19,5 @@ module LightService
20
19
  logger
21
20
  end
22
21
  end
23
-
24
22
  end
25
23
  end
@@ -7,28 +7,32 @@ module LightService
7
7
  class Context < Hash
8
8
  attr_accessor :message, :error_code, :current_action
9
9
 
10
- def initialize(context={}, outcome=Outcomes::SUCCESS, message='', error_code=nil)
11
- @outcome, @message, @error_code = outcome, message, error_code
10
+ def initialize(context = {},
11
+ outcome = Outcomes::SUCCESS,
12
+ message = '',
13
+ error_code = nil)
14
+ @outcome = outcome
15
+ @message = message
16
+ @error_code = error_code
12
17
  @skip_all = false
13
- context.to_hash.each {|k,v| self[k] = v}
18
+ context.to_hash.each { |k, v| self[k] = v }
14
19
  self
15
20
  end
16
21
 
17
- def self.make(context={})
18
- unless context.is_a? Hash or context.is_a? LightService::Context
19
- raise ArgumentError, 'Argument must be Hash or LightService::Context'
22
+ def self.make(context = {})
23
+ unless context.is_a?(Hash) || context.is_a?(LightService::Context)
24
+ msg = 'Argument must be Hash or LightService::Context'
25
+ fail ArgumentError, msg
20
26
  end
21
27
 
22
- unless context.is_a?(Context)
23
- context = self.new(context)
24
- end
28
+ context = new(context) unless context.is_a?(Context)
25
29
 
26
- context.set_aliases(context.delete(:_aliases)) if context[:_aliases]
30
+ context.assign_aliases(context.delete(:_aliases)) if context[:_aliases]
27
31
  context
28
32
  end
29
33
 
30
34
  def add_to_context(values)
31
- self.merge! values
35
+ merge! values
32
36
  end
33
37
 
34
38
  def success?
@@ -44,16 +48,20 @@ module LightService
44
48
  end
45
49
 
46
50
  def outcome
47
- ActiveSupport::Deprecation.warn '`Context#outcome` attribute reader is DEPRECATED and will be removed'
51
+ msg = '`Context#outcome` attribute reader is ' \
52
+ 'DEPRECATED and will be removed'
53
+ ActiveSupport::Deprecation.warn(msg)
48
54
  @outcome
49
55
  end
50
56
 
51
- def succeed!(message=nil, options={})
52
- @message = Configuration.localization_adapter.success(message, current_action, options)
57
+ def succeed!(message = nil, options = {})
58
+ @message = Configuration.localization_adapter.success(message,
59
+ current_action,
60
+ options)
53
61
  @outcome = Outcomes::SUCCESS
54
62
  end
55
63
 
56
- def fail!(message=nil, options_or_error_code={})
64
+ def fail!(message = nil, options_or_error_code = {})
57
65
  options_or_error_code ||= {}
58
66
 
59
67
  if options_or_error_code.is_a?(Hash)
@@ -64,17 +72,19 @@ module LightService
64
72
  options = {}
65
73
  end
66
74
 
67
- @message = Configuration.localization_adapter.failure(message, current_action, options)
75
+ @message = Configuration.localization_adapter.failure(message,
76
+ current_action,
77
+ options)
68
78
  @error_code = error_code
69
79
  @outcome = Outcomes::FAILURE
70
80
  end
71
81
 
72
- def fail_with_rollback!(message=nil, error_code=nil)
82
+ def fail_with_rollback!(message = nil, error_code = nil)
73
83
  fail!(message, error_code)
74
- raise FailWithRollbackError.new
84
+ fail(FailWithRollbackError)
75
85
  end
76
86
 
77
- def skip_all!(message=nil)
87
+ def skip_all!(message = nil)
78
88
  @message = message
79
89
  @skip_all = true
80
90
  end
@@ -86,13 +96,13 @@ module LightService
86
96
  def define_accessor_methods_for_keys(keys)
87
97
  return if keys.nil?
88
98
  keys.each do |key|
89
- next if self.respond_to?(key.to_sym)
90
- define_singleton_method("#{key}") { self.fetch(key) }
99
+ next if respond_to?(key.to_sym)
100
+ define_singleton_method(key.to_s) { fetch(key) }
91
101
  define_singleton_method("#{key}=") { |value| self[key] = value }
92
102
  end
93
103
  end
94
104
 
95
- def set_aliases(aliases)
105
+ def assign_aliases(aliases)
96
106
  @aliases = aliases
97
107
 
98
108
  aliases.each_pair do |key, key_alias|
@@ -1,114 +1,118 @@
1
- module LightService; class Context
2
- class KeyVerifier
3
- attr_reader :context, :action
1
+ module LightService
2
+ class Context
3
+ class KeyVerifier
4
+ attr_reader :context, :action
5
+
6
+ def initialize(context, action)
7
+ @context = context
8
+ @action = action
9
+ end
4
10
 
5
- def initialize(context, action)
6
- @context = context
7
- @action = action
8
- end
11
+ def are_all_keys_in_context?(keys)
12
+ not_found_keys = keys_not_found(keys)
13
+ !not_found_keys.any?
14
+ end
9
15
 
10
- def are_all_keys_in_context?(keys)
11
- not_found_keys = keys_not_found(keys)
12
- !not_found_keys.any?
13
- end
16
+ def keys_not_found(keys)
17
+ keys ||= context.keys
18
+ keys - context.keys
19
+ end
14
20
 
15
- def keys_not_found(keys)
16
- keys ||= context.keys
17
- keys - context.keys
18
- end
21
+ def format_keys(keys)
22
+ keys.map { |k| ":#{k}" }.join(', ')
23
+ end
19
24
 
20
- def format_keys(keys)
21
- keys.map { |k| ":#{k}"}.join(', ')
22
- end
25
+ def error_message
26
+ "#{type_name} #{format_keys(keys_not_found(keys))} " \
27
+ "to be in the context during #{action}"
28
+ end
23
29
 
24
- def error_message
25
- "#{type_name} #{format_keys(keys_not_found(keys))} to be in the context during #{action}"
26
- end
30
+ def throw_error_predicate(_keys)
31
+ fail NotImplementedError, 'Sorry, you have to override length'
32
+ end
27
33
 
28
- def throw_error_predicate(keys)
29
- raise NotImplementedError, 'Sorry, you have to override length'
30
- end
34
+ def verify
35
+ return context if context.failure?
31
36
 
32
- def verify
33
- return context if context.failure?
37
+ if throw_error_predicate(keys)
38
+ Configuration.logger.error error_message
39
+ fail error_to_throw, error_message
40
+ end
34
41
 
35
- if throw_error_predicate(keys)
36
- Configuration.logger.error error_message
37
- fail error_to_throw, error_message
42
+ context
38
43
  end
39
44
 
40
- context
41
- end
42
-
43
- def self.verify_keys(context, action, &block)
44
- ReservedKeysVerifier.new(context, action).verify
45
- ExpectedKeyVerifier.new(context, action).verify
45
+ def self.verify_keys(context, action, &block)
46
+ ReservedKeysVerifier.new(context, action).verify
47
+ ExpectedKeyVerifier.new(context, action).verify
46
48
 
47
- block.call
49
+ block.call
48
50
 
49
- PromisedKeyVerifier.new(context, action).verify
51
+ PromisedKeyVerifier.new(context, action).verify
52
+ end
50
53
  end
51
- end
52
54
 
53
- class ExpectedKeyVerifier < KeyVerifier
54
- def type_name
55
- "expected"
56
- end
55
+ class ExpectedKeyVerifier < KeyVerifier
56
+ def type_name
57
+ "expected"
58
+ end
57
59
 
58
- def keys
59
- action.expected_keys
60
- end
60
+ def keys
61
+ action.expected_keys
62
+ end
61
63
 
62
- def error_to_throw
63
- ExpectedKeysNotInContextError
64
- end
64
+ def error_to_throw
65
+ ExpectedKeysNotInContextError
66
+ end
65
67
 
66
- def throw_error_predicate(keys)
67
- !are_all_keys_in_context?(keys)
68
+ def throw_error_predicate(keys)
69
+ !are_all_keys_in_context?(keys)
70
+ end
68
71
  end
69
- end
70
72
 
71
- class PromisedKeyVerifier < KeyVerifier
72
- def type_name
73
- "promised"
74
- end
73
+ class PromisedKeyVerifier < KeyVerifier
74
+ def type_name
75
+ "promised"
76
+ end
75
77
 
76
- def keys
77
- action.promised_keys
78
- end
78
+ def keys
79
+ action.promised_keys
80
+ end
79
81
 
80
- def error_to_throw
81
- PromisedKeysNotInContextError
82
- end
82
+ def error_to_throw
83
+ PromisedKeysNotInContextError
84
+ end
83
85
 
84
- def throw_error_predicate(keys)
85
- !are_all_keys_in_context?(keys)
86
+ def throw_error_predicate(keys)
87
+ !are_all_keys_in_context?(keys)
88
+ end
86
89
  end
87
- end
88
90
 
89
- class ReservedKeysVerifier < KeyVerifier
90
- def violated_keys
91
- (action.promised_keys + action.expected_keys) & reserved_keys
92
- end
91
+ class ReservedKeysVerifier < KeyVerifier
92
+ def violated_keys
93
+ (action.promised_keys + action.expected_keys) & reserved_keys
94
+ end
93
95
 
94
- def error_message
95
- "promised or expected keys cannot be a reserved key: [#{format_keys(violated_keys)}]"
96
- end
96
+ def error_message
97
+ "promised or expected keys cannot be a " \
98
+ "reserved key: [#{format_keys(violated_keys)}]"
99
+ end
97
100
 
98
- def keys
99
- violated_keys
100
- end
101
+ def keys
102
+ violated_keys
103
+ end
101
104
 
102
- def error_to_throw
103
- ReservedKeysInContextError
104
- end
105
+ def error_to_throw
106
+ ReservedKeysInContextError
107
+ end
105
108
 
106
- def throw_error_predicate(keys)
107
- keys.any?
108
- end
109
+ def throw_error_predicate(keys)
110
+ keys.any?
111
+ end
109
112
 
110
- def reserved_keys
111
- [:message, :error_code, :current_action].freeze
113
+ def reserved_keys
114
+ [:message, :error_code, :current_action].freeze
115
+ end
112
116
  end
113
117
  end
114
- end; end
118
+ end
@@ -1,22 +1,25 @@
1
1
  module LightService
2
2
  class LocalizationAdapter
3
- def failure(message_or_key, action_class, i18n_options={})
3
+ def failure(message_or_key, action_class, i18n_options = {})
4
4
  find_translated_message(message_or_key,
5
5
  action_class,
6
6
  i18n_options,
7
- {:type => :failure})
7
+ :type => :failure)
8
8
  end
9
9
 
10
- def success(message_or_key, action_class, i18n_options={})
10
+ def success(message_or_key, action_class, i18n_options = {})
11
11
  find_translated_message(message_or_key,
12
12
  action_class,
13
13
  i18n_options,
14
- {:type => :success})
14
+ :type => :success)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
- def find_translated_message(message_or_key, action_class, i18n_options, type)
19
+ def find_translated_message(message_or_key,
20
+ action_class,
21
+ i18n_options,
22
+ type)
20
23
  if message_or_key.is_a?(Symbol)
21
24
  i18n_options.merge!(type)
22
25
  translate(message_or_key, action_class, i18n_options)
@@ -25,11 +28,11 @@ module LightService
25
28
  end
26
29
  end
27
30
 
28
- def translate(key, action_class, options={})
31
+ def translate(key, action_class, options = {})
29
32
  type = options.delete(:type)
30
33
 
31
34
  scope = i18n_scope_from_class(action_class, type)
32
- options.merge!(scope: scope)
35
+ options[:scope] = scope
33
36
 
34
37
  I18n.t(key, options)
35
38
  end
@@ -4,16 +4,19 @@ module LightService
4
4
  base_class.extend ClassMethods
5
5
  base_class.extend Macros
6
6
  end
7
+
7
8
  def self.included(base_class)
8
- ActiveSupport::Deprecation.warn "including LightService::Organizer is deprecated. Please use `extend LightService::Organizer` instead"
9
+ warning_msg = "including LightService::Organizer is deprecated. " \
10
+ "Please use `extend LightService::Organizer` instead"
11
+ ActiveSupport::Deprecation.warn(warning_msg)
9
12
  base_class.extend ClassMethods
10
13
  base_class.extend Macros
11
14
  end
12
15
 
13
16
  # In case this module is included
14
17
  module ClassMethods
15
- def with(data={})
16
- data.merge!(:_aliases => @aliases) if @aliases
18
+ def with(data = {})
19
+ data[:_aliases] = @aliases if @aliases
17
20
  WithReducerFactory.make(self).with(data)
18
21
  end
19
22