mini_camel 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
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