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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.md +22 -0
- data/README.md +300 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/hello_world.rb +106 -0
- data/lib/mini_camel.rb +63 -0
- data/lib/mini_camel/context.rb +5 -0
- data/lib/mini_camel/default_error_handler.rb +37 -0
- data/lib/mini_camel/dto.rb +55 -0
- data/lib/mini_camel/environment.rb +66 -0
- data/lib/mini_camel/error.rb +57 -0
- data/lib/mini_camel/exchange.rb +80 -0
- data/lib/mini_camel/exchange_error.rb +36 -0
- data/lib/mini_camel/exchange_result.rb +5 -0
- data/lib/mini_camel/interactor.rb +13 -0
- data/lib/mini_camel/processor/base.rb +14 -0
- data/lib/mini_camel/processor/each.rb +28 -0
- data/lib/mini_camel/processor/expose_field.rb +29 -0
- data/lib/mini_camel/processor/expose_fields.rb +34 -0
- data/lib/mini_camel/processor/extract_result.rb +22 -0
- data/lib/mini_camel/processor/mutate.rb +18 -0
- data/lib/mini_camel/processor/mutate_each.rb +16 -0
- data/lib/mini_camel/processor/pipeline.rb +19 -0
- data/lib/mini_camel/processor/process.rb +22 -0
- data/lib/mini_camel/processor/process_each.rb +16 -0
- data/lib/mini_camel/processor/produce.rb +17 -0
- data/lib/mini_camel/processor/to.rb +15 -0
- data/lib/mini_camel/processor/transform.rb +15 -0
- data/lib/mini_camel/processor/transform_each.rb +15 -0
- data/lib/mini_camel/processor/validate.rb +21 -0
- data/lib/mini_camel/processor/wrap_in_dto.rb +19 -0
- data/lib/mini_camel/processor_definition/base.rb +13 -0
- data/lib/mini_camel/processor_definition/each.rb +20 -0
- data/lib/mini_camel/processor_definition/expose_field.rb +28 -0
- data/lib/mini_camel/processor_definition/expose_fields.rb +19 -0
- data/lib/mini_camel/processor_definition/extract_result.rb +17 -0
- data/lib/mini_camel/processor_definition/mutate.rb +21 -0
- data/lib/mini_camel/processor_definition/mutate_each.rb +15 -0
- data/lib/mini_camel/processor_definition/pipeline.rb +17 -0
- data/lib/mini_camel/processor_definition/process.rb +19 -0
- data/lib/mini_camel/processor_definition/process_each.rb +14 -0
- data/lib/mini_camel/processor_definition/produce.rb +20 -0
- data/lib/mini_camel/processor_definition/to.rb +17 -0
- data/lib/mini_camel/processor_definition/transform.rb +17 -0
- data/lib/mini_camel/processor_definition/transform_each.rb +20 -0
- data/lib/mini_camel/processor_definition/validate.rb +26 -0
- data/lib/mini_camel/processor_definition/wrap_in_dto.rb +21 -0
- data/lib/mini_camel/route.rb +21 -0
- data/lib/mini_camel/route_builder.rb +24 -0
- data/lib/mini_camel/route_collection.rb +16 -0
- data/lib/mini_camel/route_definition.rb +146 -0
- data/lib/mini_camel/route_dispatcher.rb +37 -0
- data/lib/mini_camel/route_finalizer.rb +38 -0
- data/lib/mini_camel/route_generator.rb +32 -0
- data/lib/mini_camel/strict_dto.rb +36 -0
- data/lib/mini_camel/version.rb +3 -0
- data/mini_camel.gemspec +30 -0
- metadata +237 -0
data/lib/mini_camel.rb
ADDED
@@ -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,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,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,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
|