mini_camel 0.5.8

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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +4 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.md +22 -0
  9. data/README.md +300 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/examples/hello_world.rb +106 -0
  14. data/lib/mini_camel.rb +63 -0
  15. data/lib/mini_camel/context.rb +5 -0
  16. data/lib/mini_camel/default_error_handler.rb +37 -0
  17. data/lib/mini_camel/dto.rb +55 -0
  18. data/lib/mini_camel/environment.rb +66 -0
  19. data/lib/mini_camel/error.rb +57 -0
  20. data/lib/mini_camel/exchange.rb +80 -0
  21. data/lib/mini_camel/exchange_error.rb +36 -0
  22. data/lib/mini_camel/exchange_result.rb +5 -0
  23. data/lib/mini_camel/interactor.rb +13 -0
  24. data/lib/mini_camel/processor/base.rb +14 -0
  25. data/lib/mini_camel/processor/each.rb +28 -0
  26. data/lib/mini_camel/processor/expose_field.rb +29 -0
  27. data/lib/mini_camel/processor/expose_fields.rb +34 -0
  28. data/lib/mini_camel/processor/extract_result.rb +22 -0
  29. data/lib/mini_camel/processor/mutate.rb +18 -0
  30. data/lib/mini_camel/processor/mutate_each.rb +16 -0
  31. data/lib/mini_camel/processor/pipeline.rb +19 -0
  32. data/lib/mini_camel/processor/process.rb +22 -0
  33. data/lib/mini_camel/processor/process_each.rb +16 -0
  34. data/lib/mini_camel/processor/produce.rb +17 -0
  35. data/lib/mini_camel/processor/to.rb +15 -0
  36. data/lib/mini_camel/processor/transform.rb +15 -0
  37. data/lib/mini_camel/processor/transform_each.rb +15 -0
  38. data/lib/mini_camel/processor/validate.rb +21 -0
  39. data/lib/mini_camel/processor/wrap_in_dto.rb +19 -0
  40. data/lib/mini_camel/processor_definition/base.rb +13 -0
  41. data/lib/mini_camel/processor_definition/each.rb +20 -0
  42. data/lib/mini_camel/processor_definition/expose_field.rb +28 -0
  43. data/lib/mini_camel/processor_definition/expose_fields.rb +19 -0
  44. data/lib/mini_camel/processor_definition/extract_result.rb +17 -0
  45. data/lib/mini_camel/processor_definition/mutate.rb +21 -0
  46. data/lib/mini_camel/processor_definition/mutate_each.rb +15 -0
  47. data/lib/mini_camel/processor_definition/pipeline.rb +17 -0
  48. data/lib/mini_camel/processor_definition/process.rb +19 -0
  49. data/lib/mini_camel/processor_definition/process_each.rb +14 -0
  50. data/lib/mini_camel/processor_definition/produce.rb +20 -0
  51. data/lib/mini_camel/processor_definition/to.rb +17 -0
  52. data/lib/mini_camel/processor_definition/transform.rb +17 -0
  53. data/lib/mini_camel/processor_definition/transform_each.rb +20 -0
  54. data/lib/mini_camel/processor_definition/validate.rb +26 -0
  55. data/lib/mini_camel/processor_definition/wrap_in_dto.rb +21 -0
  56. data/lib/mini_camel/route.rb +21 -0
  57. data/lib/mini_camel/route_builder.rb +24 -0
  58. data/lib/mini_camel/route_collection.rb +16 -0
  59. data/lib/mini_camel/route_definition.rb +146 -0
  60. data/lib/mini_camel/route_dispatcher.rb +37 -0
  61. data/lib/mini_camel/route_finalizer.rb +38 -0
  62. data/lib/mini_camel/route_generator.rb +32 -0
  63. data/lib/mini_camel/strict_dto.rb +36 -0
  64. data/lib/mini_camel/version.rb +3 -0
  65. data/mini_camel.gemspec +30 -0
  66. metadata +237 -0
@@ -0,0 +1,63 @@
1
+ require "active_support"
2
+ require "active_support/core_ext"
3
+ require "active_model"
4
+ require "virtus"
5
+ require "hashie/mash"
6
+ require 'multi_json'
7
+
8
+ require "mini_camel/version"
9
+ require "mini_camel/dto"
10
+ require "mini_camel/strict_dto"
11
+ require "mini_camel/context"
12
+ require "mini_camel/exchange_error"
13
+ require "mini_camel/exchange_result"
14
+ require "mini_camel/exchange"
15
+ require "mini_camel/environment"
16
+ require "mini_camel/error"
17
+ require "mini_camel/default_error_handler"
18
+ require "mini_camel/route"
19
+ require "mini_camel/route_builder"
20
+ require "mini_camel/route_collection"
21
+ require "mini_camel/route_definition"
22
+ require "mini_camel/route_dispatcher"
23
+ require "mini_camel/route_finalizer"
24
+ require "mini_camel/route_generator"
25
+ require "mini_camel/interactor"
26
+
27
+ require 'mini_camel/processor/base'
28
+ require 'mini_camel/processor/each'
29
+ require 'mini_camel/processor/process'
30
+ require 'mini_camel/processor/process_each'
31
+ require 'mini_camel/processor/expose_field'
32
+ require 'mini_camel/processor/expose_fields'
33
+ require 'mini_camel/processor/extract_result'
34
+ require 'mini_camel/processor/pipeline'
35
+ require 'mini_camel/processor/to'
36
+ require 'mini_camel/processor/transform'
37
+ require 'mini_camel/processor/transform_each'
38
+ require 'mini_camel/processor/mutate'
39
+ require 'mini_camel/processor/mutate_each'
40
+ require 'mini_camel/processor/produce'
41
+ require 'mini_camel/processor/wrap_in_dto'
42
+ require 'mini_camel/processor/validate'
43
+
44
+ require 'mini_camel/processor_definition/base'
45
+ require 'mini_camel/processor_definition/each'
46
+ require 'mini_camel/processor_definition/process'
47
+ require 'mini_camel/processor_definition/process_each'
48
+ require 'mini_camel/processor_definition/expose_field'
49
+ require 'mini_camel/processor_definition/expose_fields'
50
+ require 'mini_camel/processor_definition/extract_result'
51
+ require 'mini_camel/processor_definition/pipeline'
52
+ require 'mini_camel/processor_definition/to'
53
+ require 'mini_camel/processor_definition/transform'
54
+ require 'mini_camel/processor_definition/transform_each'
55
+ require 'mini_camel/processor_definition/mutate'
56
+ require 'mini_camel/processor_definition/mutate_each'
57
+ require 'mini_camel/processor_definition/produce'
58
+ require 'mini_camel/processor_definition/wrap_in_dto'
59
+ require 'mini_camel/processor_definition/validate'
60
+
61
+ module MiniCamel
62
+
63
+ end
@@ -0,0 +1,5 @@
1
+ module MiniCamel
2
+ class Context < StrictDto
3
+
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ module MiniCamel
2
+ class DefaultErrorHandler
3
+ include Virtus.value_object
4
+
5
+ values do
6
+ attribute :registered_errors, Array, default: []
7
+ end
8
+
9
+ def call(error, exchange)
10
+ raise error unless error.class.in? registered_errors
11
+
12
+ exchange.set_error(assemble_exchange_error(error))
13
+ end
14
+
15
+ private
16
+
17
+ def assemble_exchange_error(error)
18
+ ExchangeError.new(
19
+ error_class: error.class,
20
+ message: error.message,
21
+ details: Dto.new(details(error)),
22
+ backtrace: error.backtrace || []
23
+ )
24
+ end
25
+
26
+ def details(error)
27
+ if error.respond_to?(:internal_errors)
28
+ error.internal_errors
29
+ else
30
+ {}
31
+ end
32
+ end
33
+
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,55 @@
1
+ module MiniCamel
2
+
3
+ class Dto < OpenStruct
4
+
5
+ delegate :to_json, :as_json, :to_hash, :keys, :to_ary, to: :table
6
+
7
+ def self.empty
8
+ new
9
+ end
10
+
11
+ # ensures that every hash like object is a dto
12
+ def self.build(hash_object)
13
+ hash_object = MultiJson.load(MultiJson.dump(self.new(hash_object)))
14
+ deep_build(hash_object)
15
+ end
16
+
17
+ # @private
18
+ def self.deep_build(hash_object)
19
+ case hash_object
20
+ when Hash
21
+ hash_object.each do |k, v|
22
+ hash_object[k] = deep_build(v)
23
+ end
24
+ self.new(hash_object)
25
+ when Array
26
+ hash_object.map{|item| deep_build(item)}
27
+ else
28
+ hash_object
29
+ end
30
+ end
31
+
32
+ def initialize(hash = {})
33
+ super
34
+ @table = Hashie::Mash.new(hash)
35
+ end
36
+
37
+ def update(data = {})
38
+ modifiable.update(data)
39
+ end
40
+
41
+ def [](key)
42
+ fetch(key)
43
+ end
44
+
45
+ def fetch(key, default: nil)
46
+ if @table.has_key?(key)
47
+ @table.fetch(key, default)
48
+ else
49
+ return default unless default.nil?
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+
@@ -0,0 +1,66 @@
1
+ module MiniCamel
2
+ class Environment
3
+ include Virtus.value_object
4
+
5
+ values do
6
+ attribute :route_builders, Array, default: []
7
+ attribute :routes, Array, default: []
8
+ attribute :finalized, Boolean, default: false
9
+
10
+ attribute :finalizer_class, Class
11
+ attribute :error_handler, Object
12
+ end
13
+
14
+ def dispatch_route(route_name, options = {})
15
+ with_data = options[:with_data] || Dto.new
16
+ RouteDispatcher.new(route: route_name, with_data: with_data, env: self).dispatch
17
+ end
18
+
19
+ def register_route_builder(*builders)
20
+ @route_builders += builders
21
+ self
22
+ end
23
+
24
+ def register_error_handler(handler)
25
+ @error_handler = handler
26
+ self
27
+ end
28
+
29
+ def add_route(route)
30
+ routes << route
31
+ end
32
+
33
+ def finalize
34
+ finalizer_class.new(env: self).finalize
35
+ self
36
+ end
37
+
38
+ def finalized!
39
+ @finalized = true
40
+ end
41
+
42
+ # @internal
43
+ def call_route(route_name, exchange)
44
+ if route = routes_by_name[route_name]
45
+ route.call(exchange)
46
+ else
47
+ raise UnknownRouteError, route_name
48
+ end
49
+ end
50
+
51
+ def finalizer_class
52
+ @finalizer_class ||= RouteFinalizer
53
+ end
54
+
55
+ def error_handler
56
+ @error_handler ||= DefaultErrorHandler.new
57
+ end
58
+
59
+ private
60
+
61
+ def routes_by_name
62
+ @routes_by_name ||= routes.index_by(&:route_name)
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,57 @@
1
+ module MiniCamel
2
+
3
+ class CamelError < StandardError; end
4
+
5
+ class EnvironmentNotFinalized < CamelError; end
6
+
7
+ class InvalidInteractor < CamelError; end
8
+
9
+ class InvalidRouteDefinition < CamelError
10
+
11
+ attr_reader :route_definition
12
+
13
+ def initialize(message, route_definition)
14
+ @route_definition = route_definition
15
+ super("#{message}: #{route_definition.class} #{route_definition.errors.full_messages}")
16
+ end
17
+
18
+ end
19
+
20
+ class InvalidProcessorDefinition < CamelError
21
+
22
+ attr_reader :processor_definition
23
+
24
+ def initialize(message, processor_definition)
25
+ @processor_definition = processor_definition
26
+ super("#{message}: #{processor_definition.class} #{processor_definition.errors.full_messages}")
27
+ end
28
+
29
+ end
30
+
31
+ class ExchangeFailure < CamelError
32
+ attr_reader :exchange_error
33
+
34
+ def initialize(message, exchange_error)
35
+ @exchange_error = exchange_error
36
+ super(message)
37
+ end
38
+ end
39
+
40
+ class ReRaisedError < CamelError
41
+ attr_reader :original_error_class
42
+
43
+ def initialize(message, original_error_class)
44
+ @original_error_class = original_error_class
45
+ super("[#{original_error_class}]: #{message}")
46
+ end
47
+ end
48
+
49
+ class UnknownRouteError < CamelError
50
+ attr_reader :route_name
51
+
52
+ def initialize(route_name)
53
+ super("Route not found: '#{route_name}'")
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,80 @@
1
+ module MiniCamel
2
+ class Exchange
3
+ include Virtus.value_object
4
+
5
+ attribute :context, Context, reader: :private
6
+
7
+ values do
8
+ attribute :result, ExchangeResult, reader: :private
9
+ attribute :error, ExchangeError, reader: :private
10
+ end
11
+
12
+ def success?
13
+ error.nil?
14
+ end
15
+
16
+ def failure?
17
+ !success?
18
+ end
19
+
20
+ def on(modifier)
21
+ raise ArgumentError, "Unkown modifier '#{modifier}'" unless modifier.in? [:success, :failure]
22
+
23
+ yield result if modifier == :success && success?
24
+ yield error if modifier == :failure && failure?
25
+
26
+ self
27
+ end
28
+
29
+ def result_or_else(fallback)
30
+ if success?
31
+ result
32
+ else
33
+ ExchangeResult.new(fallback)
34
+ end
35
+ end
36
+
37
+ def result_or_else_nil
38
+ result if success?
39
+ end
40
+
41
+ def result_or_else_fail!
42
+ if success?
43
+ result
44
+ else
45
+ raise ExchangeFailure.new("Exchange failed!", error)
46
+ end
47
+ end
48
+
49
+ def result_or_else_try
50
+ if success?
51
+ result
52
+ else
53
+ yield error
54
+ end
55
+ end
56
+
57
+ def update_context(params = {})
58
+ context.update(params)
59
+ end
60
+
61
+ def context_fetch(field_name, default: nil)
62
+ context.fetch(field_name, default: default)
63
+ end
64
+
65
+ def set_result(exchange_result)
66
+ self.result = exchange_result
67
+ end
68
+
69
+ def set_error(exchange_error)
70
+ self.error = exchange_error
71
+ end
72
+
73
+ private
74
+
75
+ def context
76
+ @context ||= Context.empty
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,36 @@
1
+ module MiniCamel
2
+ class ExchangeError
3
+ include Virtus.value_object
4
+
5
+ values do
6
+ attribute :error_class, Class, reader: :private
7
+ attribute :message, String, reader: :private
8
+ attribute :details, Dto, reader: :private
9
+ end
10
+
11
+ attribute :backtrace, Array, default: []
12
+
13
+ def on(check_error_class)
14
+ yield message, details if check_error_class == error_class
15
+
16
+ self
17
+ end
18
+
19
+ # This is just a helper method.
20
+ # Do not use it in production code!
21
+ def raise!
22
+ raise ReRaisedError.new(message, error_class)
23
+ end
24
+
25
+ def as_json(options = {})
26
+ {error_class: error_class.name, message: message, details: details}.as_json(options)
27
+ end
28
+
29
+ private
30
+
31
+ def details
32
+ @details ||= Dto.empty
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ module MiniCamel
2
+ class ExchangeResult < StrictDto
3
+
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module MiniCamel
2
+ class Interactor
3
+ include Virtus.value_object
4
+ include ActiveModel::Validations
5
+
6
+ def call
7
+ raise InvalidInteractor, "Invalid interactor '#{self.class.name}': #{self.errors.full_messages}." if invalid?
8
+
9
+ run
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module MiniCamel
2
+ module Processor
3
+ class Base
4
+ include Virtus.value_object
5
+
6
+ attribute :env, Environment
7
+
8
+ def call(exchange)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ module MiniCamel
2
+ module Processor
3
+ class Each < Base
4
+
5
+ values do
6
+ attribute :field, Symbol
7
+ attribute :in_field, Symbol
8
+ attribute :additional_fields, [Symbol]
9
+ attribute :with_class, Class
10
+ end
11
+
12
+ private
13
+
14
+ def process(entry, additional_data)
15
+ with_class.new(additional_data.merge(field => entry)).call
16
+ end
17
+
18
+ def fetch_additional_data(exchange)
19
+ additional_fields.map{|f| {f => exchange.context_fetch(f)}}.reduce(&:merge) || {}
20
+ end
21
+
22
+ def fetch_collection(exchange)
23
+ exchange.context_fetch(in_field)
24
+ end
25
+
26
+ end
27
+ end
28
+ end