functional-light-service 0.5.4 → 6.0.0

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/project-build.yml +35 -11
  3. data/.rubocop.yml +101 -160
  4. data/AUDIT-functional-light-service.md +352 -0
  5. data/CHANGELOG.md +38 -0
  6. data/README.md +54 -2
  7. data/audit/bench.rb +99 -0
  8. data/audit/verify_findings.rb +172 -0
  9. data/functional-light-service.gemspec +15 -21
  10. data/lib/functional-light-service/action.rb +97 -101
  11. data/lib/functional-light-service/configuration.rb +26 -24
  12. data/lib/functional-light-service/context/key_verifier.rb +124 -118
  13. data/lib/functional-light-service/context.rb +63 -20
  14. data/lib/functional-light-service/deprecations.rb +26 -0
  15. data/lib/functional-light-service/errors.rb +8 -6
  16. data/lib/functional-light-service/functional/enum.rb +286 -250
  17. data/lib/functional-light-service/functional/maybe.rb +21 -15
  18. data/lib/functional-light-service/functional/monad.rb +77 -66
  19. data/lib/functional-light-service/functional/null.rb +88 -74
  20. data/lib/functional-light-service/functional/option.rb +100 -97
  21. data/lib/functional-light-service/functional/result.rb +129 -116
  22. data/lib/functional-light-service/localization_adapter.rb +48 -47
  23. data/lib/functional-light-service/organizer/execute.rb +16 -14
  24. data/lib/functional-light-service/organizer/iterate.rb +30 -25
  25. data/lib/functional-light-service/organizer/reduce_if.rb +19 -17
  26. data/lib/functional-light-service/organizer/reduce_until.rb +22 -20
  27. data/lib/functional-light-service/organizer/scoped_reducable.rb +15 -13
  28. data/lib/functional-light-service/organizer/with_callback.rb +28 -26
  29. data/lib/functional-light-service/organizer/with_reducer.rb +81 -77
  30. data/lib/functional-light-service/organizer/with_reducer_factory.rb +20 -18
  31. data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +110 -108
  32. data/lib/functional-light-service/organizer.rb +114 -114
  33. data/lib/functional-light-service/testing/context_factory.rb +48 -42
  34. data/lib/functional-light-service/testing.rb +3 -1
  35. data/lib/functional-light-service/version.rb +5 -3
  36. data/lib/functional-light-service.rb +30 -28
  37. data/spec/acceptance/after_actions_spec.rb +87 -71
  38. data/spec/acceptance/before_actions_spec.rb +115 -98
  39. data/spec/acceptance/custom_log_from_organizer_spec.rb +61 -60
  40. data/spec/acceptance/deprecation_warnings_spec.rb +82 -0
  41. data/spec/acceptance/fail_spec.rb +52 -50
  42. data/spec/acceptance/message_localization_spec.rb +119 -118
  43. data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +68 -65
  44. data/spec/acceptance/organizer/reduce_if_spec.rb +89 -89
  45. data/spec/acceptance/organizer/with_callback_spec.rb +113 -110
  46. data/spec/acceptance/{not_having_call_method_warning_spec.rb → organizer_entry_point_spec.rb} +10 -7
  47. data/spec/acceptance/rollback_spec.rb +183 -132
  48. data/spec/action_expects_and_promises_spec.rb +97 -93
  49. data/spec/action_promised_keys_spec.rb +126 -122
  50. data/spec/context_spec.rb +289 -197
  51. data/spec/examples/controller_spec.rb +63 -63
  52. data/spec/examples/validate_address_spec.rb +38 -37
  53. data/spec/lib/deterministic/currify_spec.rb +90 -88
  54. data/spec/lib/deterministic/null_spec.rb +6 -1
  55. data/spec/lib/deterministic/option_spec.rb +140 -137
  56. data/spec/lib/deterministic/result/result_map_spec.rb +155 -154
  57. data/spec/lib/deterministic/result/result_shared.rb +3 -2
  58. data/spec/lib/deterministic/result_spec.rb +2 -2
  59. data/spec/lib/edge_cases_spec.rb +156 -0
  60. data/spec/lib/enum_spec.rb +1 -1
  61. data/spec/lib/native_pattern_matching_spec.rb +74 -0
  62. data/spec/organizer_spec.rb +115 -114
  63. data/spec/readme_spec.rb +45 -47
  64. data/spec/sample/calculates_order_tax_action_spec.rb +16 -16
  65. data/spec/sample/calculates_tax_spec.rb +1 -1
  66. data/spec/sample/looks_up_tax_percentage_action_spec.rb +55 -55
  67. data/spec/sample/tax/calculates_order_tax_action.rb +10 -9
  68. data/spec/sample/tax/looks_up_tax_percentage_action.rb +28 -27
  69. data/spec/sample/tax/provides_free_shipping_action.rb +11 -10
  70. data/spec/spec_helper.rb +6 -0
  71. data/spec/test_doubles.rb +628 -599
  72. data/spec/testing/context_factory_spec.rb +21 -0
  73. metadata +45 -161
  74. data/lib/functional-light-service/organizer/verify_call_method_exists.rb +0 -29
  75. data/spec/acceptance/include_warning_spec.rb +0 -29
@@ -0,0 +1,172 @@
1
+ # Verifica dei finding dell'audit — eseguito contro lib/ reale
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
3
+ require 'functional-light-service'
4
+
5
+ results = []
6
+ def check(results, name)
7
+ ok, detail = yield
8
+ results << [name, ok, detail]
9
+ rescue => e
10
+ results << [name, :exception, "#{e.class}: #{e.message}"]
11
+ end
12
+
13
+ # ---------- F1: before_actions perso alla seconda chiamata ----------
14
+ class AddOne
15
+ extend FunctionalLightService::Action
16
+ expects :number
17
+ promises :number
18
+ executed { |ctx| ctx.number = ctx.number + 1 }
19
+ end
20
+
21
+ class Org1
22
+ extend FunctionalLightService::Organizer
23
+ before_actions ->(ctx) { ctx.number -= 10 if ctx.current_action == AddOne }
24
+ def self.call(number)
25
+ with(:number => number).reduce([AddOne])
26
+ end
27
+ end
28
+
29
+ check(results, "F1 before_actions perso alla 2a chiamata") do
30
+ r1 = Org1.call(0).fetch(:number) # atteso: -10 + 1 = -9
31
+ r2 = Org1.call(0).fetch(:number) # se bug: hook perso -> 1
32
+ [r1 == -9 && r2 == 1, "prima call=#{r1}, seconda call=#{r2}"]
33
+ end
34
+
35
+ # ---------- F2: Context#fetch — nessun KeyError e scrittura su read ----------
36
+ check(results, "F2a fetch(:missing) ritorna nil invece di KeyError e scrive la chiave") do
37
+ ctx = FunctionalLightService::Context.make({})
38
+ v = ctx.fetch(:missing)
39
+ [v.nil? && ctx.to_h.key?(:missing), "valore=#{v.inspect}, chiavi dopo fetch=#{ctx.keys.inspect}"]
40
+ end
41
+
42
+ check(results, "F2b fetch con default sovrascrive un valore falsy esistente") do
43
+ ctx = FunctionalLightService::Context.make(:flag => false)
44
+ v = ctx.fetch(:flag, true)
45
+ [v == true && ctx[:flag] == true, "fetch(:flag, true)=#{v.inspect}, ctx[:flag] ora=#{ctx[:flag].inspect} (era false)"]
46
+ end
47
+
48
+ # ---------- F3: alias asimmetrico lettura/scrittura ----------
49
+ check(results, "F3 scrittura su alias persa in lettura") do
50
+ ctx = FunctionalLightService::Context.make(:codice_fiscale => "ABC")
51
+ ctx.assign_aliases(:codice_fiscale => :cf)
52
+ ctx[:cf] = "NUOVO" # scrive la chiave :cf direttamente
53
+ read = ctx[:cf] # legge tradotto -> :codice_fiscale -> "ABC"
54
+ [read == "ABC", "dopo ctx[:cf]='NUOVO', ctx[:cf]=#{read.inspect}; hash=#{ctx.to_h.inspect}"]
55
+ end
56
+
57
+ # ---------- F4: accessor non definito per chiavi che collidono con metodi Hash ----------
58
+ class UsesSize
59
+ extend FunctionalLightService::Action
60
+ expects :size
61
+ executed { |ctx| ctx[:observed] = ctx.size } # l'utente si aspetta il valore di :size
62
+ end
63
+
64
+ check(results, "F4 expects :size -> accessor non definito, ritorna Hash#size") do
65
+ result = UsesSize.execute(:size => 999)
66
+ [result[:observed] != 999, "ctx.size dentro l'action=#{result[:observed].inspect} (atteso dal punto di vista utente: 999)"]
67
+ end
68
+
69
+ # ---------- F5: @ctx a livello di classe Action (retention + race) ----------
70
+ check(results, "F5 la classe Action trattiene l'ultimo context in @ctx") do
71
+ AddOne.execute(:number => 5)
72
+ held = AddOne.instance_variable_get(:@ctx)
73
+ [held.is_a?(FunctionalLightService::Context), "AddOne @ctx = #{held.inspect[0,80]}"]
74
+ end
75
+
76
+ # ---------- F6: fail! muta l'hash di opzioni del chiamante ----------
77
+ check(results, "F6 fail! cancella :error_code dall'hash del chiamante") do
78
+ ctx = FunctionalLightService::Context.make({})
79
+ opts = { :error_code => 500 }
80
+ ctx.fail!("boom", opts)
81
+ [!opts.key?(:error_code), "opts dopo fail! = #{opts.inspect}"]
82
+ end
83
+
84
+ # ---------- F7: Null#respond_to? con firma sbagliata ----------
85
+ check(results, "F7 Null#respond_to?(m, true) solleva ArgumentError") do
86
+ begin
87
+ Null.instance.respond_to?(:foo, true)
88
+ [false, "nessuna eccezione"]
89
+ rescue ArgumentError => e
90
+ [true, "ArgumentError: #{e.message}"]
91
+ end
92
+ end
93
+
94
+ # ---------- F8: Context#[] con aliases usa Hash#key (reverse lookup O(n)) ----------
95
+ check(results, "F8 lettura di chiave originale con molti alias resta corretta (sanity)") do
96
+ ctx = FunctionalLightService::Context.make(:a => 1)
97
+ ctx.assign_aliases(:a => :b)
98
+ [ctx[:b] == 1 && ctx[:a] == 1, "ctx[:a]=#{ctx[:a]}, ctx[:b]=#{ctx[:b]}"]
99
+ end
100
+
101
+ # ---------- F9: skip_remaining! dentro iterate viene resettato ad ogni item ----------
102
+ class SkipAll
103
+ extend FunctionalLightService::Action
104
+ executed { |ctx| ctx.skip_remaining!("basta") if ctx[:counter] == 2 }
105
+ end
106
+ class CollectAction
107
+ extend FunctionalLightService::Action
108
+ executed { |ctx| (ctx[:seen] ||= []) << ctx[:counter] }
109
+ end
110
+ class OrgIter
111
+ extend FunctionalLightService::Organizer
112
+ def self.call(ctx)
113
+ with(ctx).reduce([iterate(:counters, [SkipAll, CollectAction])])
114
+ end
115
+ end
116
+
117
+ check(results, "F9 skip_remaining! dentro iterate NON ferma l'iterazione") do
118
+ r = OrgIter.call(:counters => [1, 2, 3])
119
+ [r[:seen] == [1, 3], "seen=#{r[:seen].inspect} (2 saltato, ma 3 processato: lo skip e' stato resettato)"]
120
+ end
121
+
122
+ # ---------- F10: succeed! + message perso da reset_skip_remaining! in scoped_reduce ----------
123
+ check(results, "F10 reset_skip_remaining! azzera anche message/outcome") do
124
+ ctx = FunctionalLightService::Context.make({})
125
+ ctx.succeed!("fatto bene")
126
+ ctx.reset_skip_remaining!
127
+ [ctx.message == '', "message dopo reset=#{ctx.message.inspect}"]
128
+ end
129
+
130
+ # ---------- F11: Context#select/map degradano a Hash ----------
131
+ check(results, "F11 Context#select ritorna Hash, non Context (perde outcome)") do
132
+ ctx = FunctionalLightService::Context.make(:a => 1)
133
+ sel = ctx.select { |_k, _v| true }
134
+ [!sel.is_a?(FunctionalLightService::Context), "select.class=#{sel.class}"]
135
+ end
136
+
137
+ # ---------- F12: Some(nil) e' costruibile ----------
138
+ check(results, "F12 Some(nil) e' consentito (Option non valida il nil)") do
139
+ s = FunctionalLightService::Option::Some.new(nil)
140
+ [s.some? && s.value.nil?, "Some(nil).some?=#{s.some?}, value=nil"]
141
+ end
142
+
143
+ # ---------- F13: rollback con azione duplicata nella lista ----------
144
+ class RollA
145
+ extend FunctionalLightService::Action
146
+ executed { |ctx| (ctx[:trace] ||= []) << :a }
147
+ rolled_back { |ctx| (ctx[:rb] ||= []) << :a }
148
+ end
149
+ class RollB
150
+ extend FunctionalLightService::Action
151
+ executed { |ctx| (ctx[:trace] ||= []) << :b; ctx.fail_with_rollback!("ko") if ctx[:trace].count(:b) == 2 }
152
+ rolled_back { |ctx| (ctx[:rb] ||= []) << :b }
153
+ end
154
+ class OrgRoll
155
+ extend FunctionalLightService::Organizer
156
+ def self.call(ctx)
157
+ with(ctx).reduce([RollB, RollA, RollB]) # RollB duplicata; fallisce la SECONDA RollB
158
+ end
159
+ end
160
+
161
+ check(results, "F13 rollback con azione duplicata: index trova la 1a occorrenza -> rollback parziale") do
162
+ r = OrgRoll.call({})
163
+ # eseguite: B, A, B(fail). Rollback atteso: B, A, B. Con il bug: index(RollB)=0 -> solo [RollB].take(1) -> rollback solo B
164
+ [r[:rb] == [:b], "trace=#{r[:trace].inspect}, rollback eseguiti=#{r[:rb].inspect} (attesi: [:b, :a, :b])"]
165
+ end
166
+
167
+ puts
168
+ results.each do |name, ok, detail|
169
+ status = ok == true ? "CONFERMATO" : (ok == :exception ? "ECCEZIONE " : "NON RIPRODOTTO")
170
+ puts "[#{status}] #{name}"
171
+ puts " -> #{detail}"
172
+ end
@@ -1,39 +1,33 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require File.expand_path('../lib/functional-light-service/version', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |gem|
5
4
  gem.authors = ["Boscolo Michele"]
6
5
  gem.email = ["miboscol@gmail.com"]
7
- gem.description = %q{A service skeleton with an emphasis on simplicity with a pinch a functional programming}
6
+ gem.description = %q{FunctionalLightService combines the Organizer/Action/Context pattern of LightService with functional programming constructs (Result/Option monads, pattern matching) inspired by Deterministic: complex workflows are organized into small single-purpose actions with functional error handling.}
8
7
  gem.summary = %q{A service skeleton with an emphasis on simplicity with a pinch a functional programming}
9
8
  gem.homepage = "https://github.com/sphynx79/functional-light-service"
10
9
  gem.license = "MIT"
11
10
 
12
11
  gem.files = `git ls-files`.split($\)
13
12
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
13
  gem.name = "functional-light-service"
16
14
  gem.require_paths = ["lib"]
17
15
  gem.version = FunctionalLightService::VERSION
18
- gem.required_ruby_version = '>= 2.6.0'
16
+ gem.required_ruby_version = '>= 3.1.0'
19
17
 
20
- gem.add_runtime_dependency("dry-inflector", "~> 0.2", ">= 0.2.1")
18
+ gem.add_runtime_dependency("dry-inflector", ">= 0.2.1", "< 2")
21
19
  gem.add_runtime_dependency("i18n", "~> 1.8", ">= 1.8.11")
22
-
20
+ # logger non e' piu una default gem da Ruby 3.5/4.0: senza questa
21
+ # dichiarazione `require 'logger'` fallisce sotto Bundler
22
+ gem.add_runtime_dependency("logger", "~> 1.5")
23
23
 
24
- gem.add_development_dependency("rake", "~> 13.0.6", ">= 13.0.6")
25
- gem.add_development_dependency("i18n", "~> 1.8", ">= 1.8.11")
26
- gem.add_development_dependency("dry-inflector", "~> 0.2", ">= 0.2.1")
27
- gem.add_development_dependency("rspec", "~> 3.10.0")
28
- gem.add_development_dependency("rspec-mocks", "= 3.10.2")
29
- gem.add_development_dependency("simplecov", "~> 0.21.2")
30
- gem.add_development_dependency("simplecov-cobertura", "~> 2.1.0")
31
- # rexml >= 3.3 ha un parser XML piu severo che rompe simplecov-cobertura 2.1.0
32
- # (Malformed XML: No root element). Blocco alla 3.2.x compatibile.
33
- gem.add_development_dependency("rexml", "< 3.3")
34
- gem.add_development_dependency("rubocop", "~> 1.25.0")
35
- gem.add_development_dependency("rubocop-performance", "~> 1.13.2")
36
- gem.add_development_dependency("pry", "~> 0.14.1")
37
- gem.add_development_dependency("solargraph", "~> 0.44.2")
38
- gem.add_development_dependency("nokogiri", "~> 1.12.5")
24
+ gem.add_development_dependency("rake", "~> 13.0")
25
+ gem.add_development_dependency("rspec", "~> 3.13")
26
+ gem.add_development_dependency("simplecov", "~> 0.22")
27
+ gem.add_development_dependency("simplecov-cobertura", "~> 3.0")
28
+ gem.add_development_dependency("rubocop", "~> 1.75")
29
+ gem.add_development_dependency("rubocop-performance", "~> 1.20")
30
+ gem.add_development_dependency("pry", "~> 0.15")
31
+ gem.add_development_dependency("solargraph", "~> 0.50")
32
+ gem.add_development_dependency("benchmark-ips", "~> 2.13")
39
33
  end
@@ -1,101 +1,97 @@
1
- module FunctionalLightService
2
- module Action
3
- def self.extended(base_class)
4
- base_class.extend Macros
5
- base_class.extend FunctionalLightService::Prelude::Result
6
- end
7
-
8
- def self.included(base_class)
9
- msg = "DEPRECATION WARNING:\n" \
10
- "Including FunctionalLightService::Action is deprecated\n" \
11
- "Please use `extend FunctionalLightService::Action` instead"
12
- print msg
13
- base_class.extend Macros
14
- end
15
-
16
- module Macros
17
- def expects(*args)
18
- expected_keys.concat(args)
19
- end
20
-
21
- def promises(*args)
22
- promised_keys.concat(args)
23
- end
24
-
25
- def expected_keys
26
- @expected_keys ||= []
27
- end
28
-
29
- def promised_keys
30
- @promised_keys ||= []
31
- end
32
-
33
- def ctx(*args)
34
- @ctx ||= args
35
- end
36
-
37
- def executed
38
- define_singleton_method :execute do |context = {}|
39
- action_context = create_action_context(context)
40
- return action_context if action_context.stop_processing?
41
-
42
- @ctx = action_context
43
-
44
- # Store the action within the context
45
- action_context.current_action = self
46
-
47
- Context::KeyVerifier.verify_keys(action_context, self) do
48
- action_context.define_accessor_methods_for_keys(all_keys)
49
-
50
- catch(:jump_when_failed) do
51
- call_before_action(action_context)
52
- yield(action_context)
53
- call_after_action(action_context)
54
- end
55
- end
56
- end
57
- end
58
-
59
- def rolled_back
60
- msg = "`rolled_back` macro can not be invoked again"
61
- raise msg if respond_to?(:rollback)
62
-
63
- define_singleton_method :rollback do |context = {}|
64
- yield(context)
65
-
66
- context
67
- end
68
- end
69
-
70
- private
71
-
72
- def create_action_context(context)
73
- return context if context.is_a? FunctionalLightService::Context
74
-
75
- FunctionalLightService::Context.make(context)
76
- end
77
-
78
- def all_keys
79
- expected_keys + promised_keys
80
- end
81
-
82
- def call_before_action(context)
83
- invoke_callbacks(context[:_before_actions], context)
84
- end
85
-
86
- def call_after_action(context)
87
- invoke_callbacks(context[:_after_actions], context)
88
- end
89
-
90
- def invoke_callbacks(callbacks, context)
91
- return context unless callbacks
92
-
93
- callbacks.each do |cb|
94
- cb.call(context)
95
- end
96
-
97
- context
98
- end
99
- end
100
- end
101
- end
1
+ # frozen_string_literal: true
2
+
3
+ module FunctionalLightService
4
+ module Action
5
+ def self.extended(base_class)
6
+ base_class.extend Macros
7
+ base_class.extend FunctionalLightService::Prelude::Result
8
+ end
9
+
10
+ def self.included(base_class)
11
+ FunctionalLightService::Deprecations.warn(
12
+ "Including FunctionalLightService::Action is deprecated; " \
13
+ "use `extend FunctionalLightService::Action` instead"
14
+ )
15
+ base_class.extend Macros
16
+ end
17
+
18
+ module Macros
19
+ def expects(*args)
20
+ expected_keys.concat(args)
21
+ end
22
+
23
+ def promises(*args)
24
+ promised_keys.concat(args)
25
+ end
26
+
27
+ def expected_keys
28
+ @expected_keys ||= []
29
+ end
30
+
31
+ def promised_keys
32
+ @promised_keys ||= []
33
+ end
34
+
35
+ def executed
36
+ define_singleton_method :execute do |context = {}|
37
+ action_context = create_action_context(context)
38
+ return action_context if action_context.stop_processing?
39
+
40
+ # Store the action within the context
41
+ action_context.current_action = self
42
+
43
+ Context::KeyVerifier.verify_keys(action_context, self) do
44
+ action_context.define_accessor_methods_for_keys(all_keys)
45
+
46
+ catch(:jump_when_failed) do
47
+ call_before_action(action_context)
48
+ yield(action_context)
49
+ call_after_action(action_context)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def rolled_back
56
+ msg = "`rolled_back` macro can not be invoked again"
57
+ raise msg if respond_to?(:rollback)
58
+
59
+ define_singleton_method :rollback do |context = {}|
60
+ yield(context)
61
+
62
+ context
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def create_action_context(context)
69
+ return context if context.is_a? FunctionalLightService::Context
70
+
71
+ FunctionalLightService::Context.make(context)
72
+ end
73
+
74
+ def all_keys
75
+ expected_keys + promised_keys
76
+ end
77
+
78
+ def call_before_action(context)
79
+ invoke_callbacks(context[:_before_actions], context)
80
+ end
81
+
82
+ def call_after_action(context)
83
+ invoke_callbacks(context[:_after_actions], context)
84
+ end
85
+
86
+ def invoke_callbacks(callbacks, context)
87
+ return context unless callbacks
88
+
89
+ callbacks.each do |cb|
90
+ cb.call(context)
91
+ end
92
+
93
+ context
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,24 +1,26 @@
1
- module FunctionalLightService
2
- class Configuration
3
- class << self
4
- attr_writer :logger, :localization_adapter
5
-
6
- def logger
7
- @logger = _default_logger unless instance_variable_defined?("@logger")
8
- @logger
9
- end
10
-
11
- def localization_adapter
12
- @localization_adapter ||= LocalizationAdapter.new
13
- end
14
-
15
- private
16
-
17
- def _default_logger
18
- logger = Logger.new(nil)
19
- logger.level = Logger::WARN
20
- logger
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module FunctionalLightService
4
+ class Configuration
5
+ class << self
6
+ attr_writer :logger, :localization_adapter
7
+
8
+ def logger
9
+ @logger = _default_logger unless instance_variable_defined?("@logger")
10
+ @logger
11
+ end
12
+
13
+ def localization_adapter
14
+ @localization_adapter ||= LocalizationAdapter.new
15
+ end
16
+
17
+ private
18
+
19
+ def _default_logger
20
+ logger = Logger.new(nil)
21
+ logger.level = Logger::WARN
22
+ logger
23
+ end
24
+ end
25
+ end
26
+ end