mtk_framework 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/test.yml +21 -0
- data/.rspec +1 -0
- data/Gemfile +22 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/mtk_framework.rb +50 -0
- data/lib/mtk_framework/active_interaction_concerns/i18nable.rb +18 -0
- data/lib/mtk_framework/active_interaction_concerns/interruptable.rb +32 -0
- data/lib/mtk_framework/active_interaction_concerns/loggable.rb +84 -0
- data/lib/mtk_framework/active_interaction_concerns/rescuable.rb +27 -0
- data/lib/mtk_framework/active_interaction_concerns/updatable_object.rb +32 -0
- data/lib/mtk_framework/active_interaction_mocks/interaction_group_mocks_helper.rb +32 -0
- data/lib/mtk_framework/active_interaction_mocks/interaction_mocks_helper.rb +61 -0
- data/lib/mtk_framework/active_interaction_mocks/mocks_loader.rb +53 -0
- data/lib/mtk_framework/active_interaction_params.rb +16 -0
- data/lib/mtk_framework/active_interaction_params/parametrize_filter.rb +108 -0
- data/lib/mtk_framework/core_extensions/array/except.rb +7 -0
- data/lib/mtk_framework/core_extensions/class/virtual_method.rb +11 -0
- data/lib/mtk_framework/core_extensions/hash/rename_keys.rb +11 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/base.rb +20 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/abstract_tz_filter.rb +28 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/hash_filter.rb +38 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_account_filter.rb +23 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_contract_address_filter.rb +23 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_operation_filter.rb +23 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_public_key_filter.rb +23 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_secret_key_filter.rb +23 -0
- data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_signature_filter.rb +23 -0
- data/lib/mtk_framework/locale/active_interaction.fr.yml +8 -0
- data/lib/mtk_framework/locale/fr.yml +219 -0
- data/lib/mtk_framework/railtie.rb +13 -0
- data/mtk_framework.gemspec +114 -0
- data/spec/active_interaction_concerns/interruptable_spec.rb +127 -0
- data/spec/active_interaction_concerns/loggable_spec.rb +195 -0
- data/spec/application_interaction_spec.rb +17 -0
- data/spec/fake_app.rb +14 -0
- data/spec/gem_extensions/active_interaction/filters/tz_account_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters/tz_contract_address_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters/tz_operation_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters/tz_public_key_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters/tz_secret_key_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters/tz_signature_filter_spec.rb +7 -0
- data/spec/gem_extensions/active_interaction/filters_shared.rb +253 -0
- data/spec/gem_extensions/active_interaction/tz_filters_shared.rb +60 -0
- data/spec/spec_helper.rb +24 -0
- metadata +232 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MtkFramework
|
4
|
+
module ActiveInteractionMocks
|
5
|
+
module InteractionMocksHelper
|
6
|
+
def mock_interaction(
|
7
|
+
klass,
|
8
|
+
methods: nil,
|
9
|
+
failing: false,
|
10
|
+
mandatory: true,
|
11
|
+
expected_params: nil,
|
12
|
+
additional_params: nil,
|
13
|
+
return_proc: nil,
|
14
|
+
call_original: false
|
15
|
+
)
|
16
|
+
stubbed_methods = methods || (mandatory ? [:run] : %i[run run!])
|
17
|
+
|
18
|
+
spec_method = mandatory ? :expect : :allow
|
19
|
+
const_name = failing ? 'Fail' : 'Mocked'
|
20
|
+
mocking_klass = klass.const_get(const_name)
|
21
|
+
|
22
|
+
if block_given? || return_proc.present?
|
23
|
+
mocking_klass = Class.new(mocking_klass)
|
24
|
+
test_scope = self
|
25
|
+
|
26
|
+
mocking_klass.define_method :execute do
|
27
|
+
return_value = yield self if block_given?
|
28
|
+
if return_proc.present?
|
29
|
+
return_value = test_scope.instance_exec(&return_proc)
|
30
|
+
end
|
31
|
+
|
32
|
+
return_value
|
33
|
+
end
|
34
|
+
|
35
|
+
mocking_klass.define_singleton_method :name do
|
36
|
+
"#{klass.name}::#{const_name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
stubbed_methods.map do |stubbed_method|
|
41
|
+
block = lambda { |*params|
|
42
|
+
mocking_klass.send(stubbed_method, *params, &block)
|
43
|
+
}
|
44
|
+
|
45
|
+
rspec_sentence = receive(stubbed_method, &block)
|
46
|
+
|
47
|
+
if expected_params
|
48
|
+
with = expected_params.respond_to?(:call) ? instance_eval(&expected_params) : expected_params
|
49
|
+
rspec_sentence.with(with, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
additional_params&.call(rspec_sentence)
|
53
|
+
|
54
|
+
rspec_sentence.and_call_original if call_original
|
55
|
+
|
56
|
+
send(spec_method, klass).to rspec_sentence
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MtkFramework
|
4
|
+
module ActiveInteractionMocks
|
5
|
+
class MocksLoader
|
6
|
+
def run
|
7
|
+
# force require of all interactions
|
8
|
+
Dir['app/interactions/**/*.rb'].each do |x|
|
9
|
+
require Rails.root.join(x)
|
10
|
+
rescue StandardError
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
ApplicationInteraction.descendants.each do |klass|
|
15
|
+
mocked = Class.new(ApplicationInteraction) do
|
16
|
+
import_filters klass
|
17
|
+
|
18
|
+
# delegate i18n translation to mocked class
|
19
|
+
define_singleton_method :human_attribute_name do |*args|
|
20
|
+
klass.human_attribute_name(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
define_singleton_method :model_name do |*args|
|
24
|
+
klass.model_name(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method :to_model do
|
28
|
+
klass.to_s.split('::').first.singularize.safe_constantize&.new
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def execute; end
|
34
|
+
end
|
35
|
+
|
36
|
+
failing = Class.new(mocked) do
|
37
|
+
private
|
38
|
+
|
39
|
+
def execute
|
40
|
+
errors.add(:base, 'shit happens')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
klass.const_set('Mocked', mocked)
|
45
|
+
klass.const_set('Fail', failing)
|
46
|
+
end
|
47
|
+
|
48
|
+
require_relative 'interaction_mocks_helper.rb'
|
49
|
+
require_relative 'interaction_group_mocks_helper.rb'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'active_interaction_params/parametrize_filter.rb'
|
4
|
+
|
5
|
+
module MtkFramework
|
6
|
+
module ActiveInteractionParams
|
7
|
+
def params_from_interaction(klass, except: [])
|
8
|
+
params do
|
9
|
+
klass.filters.except(*except).each do |_, filter|
|
10
|
+
ParametrizeFilter.call(filter, self)
|
11
|
+
yield self if block_given?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MtkFramework
|
4
|
+
module ActiveInteractionParams
|
5
|
+
class ParametrizeFilter
|
6
|
+
TYPES_MAPPING = {
|
7
|
+
'Integer' => Integer,
|
8
|
+
'Float' => Float,
|
9
|
+
'Boolean' => Grape::API::Boolean,
|
10
|
+
'String' => String,
|
11
|
+
'Symbol' => Symbol,
|
12
|
+
'Date' => Date,
|
13
|
+
'DateTime' => DateTime,
|
14
|
+
'Time' => Time,
|
15
|
+
'File' => File,
|
16
|
+
'Hash' => Hash,
|
17
|
+
'Array' => Array,
|
18
|
+
'TzSecretKey' => String,
|
19
|
+
'TzAccount' => String,
|
20
|
+
'TzContractAddress' => String,
|
21
|
+
'TzPublicKey' => String,
|
22
|
+
'TzSignature' => String
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
class <<self
|
26
|
+
# TODO: handle the case of Object, Record, Interface(?)
|
27
|
+
def call(filter, params_scope)
|
28
|
+
unless nestable_filter?(filter)
|
29
|
+
return params_scope.send(grape_method(filter), filter.name,
|
30
|
+
**grape_options(filter))
|
31
|
+
end
|
32
|
+
|
33
|
+
parametrize_nestable(filter, params_scope)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parametrize_nestable(filter, params_scope)
|
37
|
+
current_filter = filter
|
38
|
+
|
39
|
+
params_scope.send(grape_method(current_filter), current_filter.name,
|
40
|
+
**grape_options(current_filter)) do
|
41
|
+
current_filter.filters.each do |_, child_filter|
|
42
|
+
unless ParametrizeFilter.array_hash_filters?(current_filter, child_filter)
|
43
|
+
ParametrizeFilter.call(child_filter, self)
|
44
|
+
end
|
45
|
+
|
46
|
+
# skip the hash require in the case of an array of hashes (AI and grape handle this case differently)
|
47
|
+
child_filter.filters.each do |_, small_child_filter|
|
48
|
+
ParametrizeFilter.call(small_child_filter, self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def grape_filter_type(filter)
|
55
|
+
if filter.is_a? ActiveInteraction::ArrayFilter
|
56
|
+
return array_grape_filter_type(filter)
|
57
|
+
end
|
58
|
+
|
59
|
+
filter_name = filter.class.name.split('::').second.split('Filter').first
|
60
|
+
|
61
|
+
TYPES_MAPPING.fetch(filter_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns Array[<File | Integer ...>] if not array of hashes
|
65
|
+
# else return Array, because in this case we use nested params with a block
|
66
|
+
def array_grape_filter_type(filter)
|
67
|
+
child_filter = filter.filters.values.first
|
68
|
+
|
69
|
+
unless child_filter.is_a? ActiveInteraction::HashFilter
|
70
|
+
return Array[grape_filter_type(child_filter)]
|
71
|
+
end
|
72
|
+
|
73
|
+
Array
|
74
|
+
end
|
75
|
+
|
76
|
+
def grape_options(filter)
|
77
|
+
grape_options = { desc: filter.options.fetch(:desc, ''), type: grape_filter_type(filter) }
|
78
|
+
if filter.options[:default]
|
79
|
+
grape_options[:default] = filter.options[:default]
|
80
|
+
end
|
81
|
+
|
82
|
+
grape_options
|
83
|
+
end
|
84
|
+
|
85
|
+
def grape_method(filter)
|
86
|
+
filter.options.key?(:default) ? :optional : :requires
|
87
|
+
end
|
88
|
+
|
89
|
+
def array_hash_filters?(filter, child_filter)
|
90
|
+
filter.is_a?(ActiveInteraction::ArrayFilter) && child_filter.is_a?(ActiveInteraction::HashFilter)
|
91
|
+
end
|
92
|
+
|
93
|
+
def nestable_filter?(filter)
|
94
|
+
unless filter.is_a? ActiveInteraction::ArrayFilter
|
95
|
+
return filter.filters.any?
|
96
|
+
end
|
97
|
+
|
98
|
+
# this case is not supposed to happen since ActiveInteraction only allows one type in the case of an Array
|
99
|
+
raise NotImplementedError unless filter.filters.count == 1
|
100
|
+
|
101
|
+
# if it is an array of hashes => we use nested params with a block
|
102
|
+
# else we use types like Array[String] => not nestable
|
103
|
+
filter.filters.values.first.is_a? ActiveInteraction::HashFilter
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class Base
|
5
|
+
def self.import_filters_optionally(klass, options = {})
|
6
|
+
only = options[:only]
|
7
|
+
except = options[:except]
|
8
|
+
default_value = options[:default_value]
|
9
|
+
|
10
|
+
other_filters = klass.filters.dup
|
11
|
+
other_filters.select! { |k, _| [*only].include?(k) } if only
|
12
|
+
other_filters.reject! { |k, _| [*except].include?(k) } if except
|
13
|
+
|
14
|
+
other_filters.each_value do |filter|
|
15
|
+
filter.options[:default] = default_value
|
16
|
+
initialize_filter(filter)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
# @abstract
|
5
|
+
#
|
6
|
+
# Common logic for filters that handle numeric objects.
|
7
|
+
#
|
8
|
+
# @private
|
9
|
+
class AbstractTzFilter < Filter
|
10
|
+
private
|
11
|
+
|
12
|
+
def matches?(value)
|
13
|
+
value.is_a?(String) && valid_tz_entry?(value)
|
14
|
+
rescue NoMethodError # BasicObject
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_tz_entry?(value)
|
19
|
+
TezosClient.new.decode_tz(value) do |prefix, _payload|
|
20
|
+
return false unless prefixes.include? prefix
|
21
|
+
end
|
22
|
+
|
23
|
+
true
|
24
|
+
rescue ArgumentError
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_interaction'
|
4
|
+
|
5
|
+
# credits to : https://github.com/formigarafa/active_interaction/pull/2
|
6
|
+
# This allows to import_filters inside hash. Example :
|
7
|
+
# hash :user do
|
8
|
+
# import_filters UserSignup
|
9
|
+
# end
|
10
|
+
|
11
|
+
module ActiveInteraction
|
12
|
+
class HashFilter < Filter
|
13
|
+
# Import filters from another interaction.
|
14
|
+
#
|
15
|
+
# @param klass [Class] The other interaction.
|
16
|
+
# @param options [Hash]
|
17
|
+
#
|
18
|
+
# @option options [Array<Symbol>, nil] :only Import only these filters.
|
19
|
+
# @option options [Array<Symbol>, nil] :except Import all filters except
|
20
|
+
# for these.
|
21
|
+
#
|
22
|
+
# @!visibility public
|
23
|
+
def import_filters(klass, options = {}) # rubocop:disable Metrics/AbcSize
|
24
|
+
only = options[:only]
|
25
|
+
except = options[:except]
|
26
|
+
groups = options[:groups] || [klass.to_s.demodulize.underscore.to_sym]
|
27
|
+
|
28
|
+
klass.filters.each do |name, filter|
|
29
|
+
next if only && ![*only].include?(name)
|
30
|
+
next if except && [*except].include?(name)
|
31
|
+
|
32
|
+
options = filter.options.merge(groups: groups)
|
33
|
+
filter_copy = filter.class.new(name, options)
|
34
|
+
filters[name] = filter_copy
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class Base
|
5
|
+
# @!method self.tz_public_key(*attributes, options = {})
|
6
|
+
# Creates accessors for the attributes and ensures that values passed to
|
7
|
+
# the attributes are Strings.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# tz_public_key :public_key
|
11
|
+
end
|
12
|
+
|
13
|
+
# @private
|
14
|
+
class TzAccountFilter < AbstractTzFilter
|
15
|
+
register :tz_account
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prefixes
|
20
|
+
%i[tz1 tz2 tz3].freeze
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_contract_address_filter.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class Base
|
5
|
+
# @!method self.tz_public_key(*attributes, options = {})
|
6
|
+
# Creates accessors for the attributes and ensures that values passed to
|
7
|
+
# the attributes are Strings.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# tz_public_key :public_key
|
11
|
+
end
|
12
|
+
|
13
|
+
# @private
|
14
|
+
class TzContractAddressFilter < AbstractTzFilter
|
15
|
+
register :tz_contract_address
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prefixes
|
20
|
+
%i[KT].freeze
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class Base
|
5
|
+
# @!method self.tz_operation(*attributes, options = {})
|
6
|
+
# Creates accessors for the attributes and ensures that values passed to
|
7
|
+
# the attributes are Strings.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# tz_operation :operation
|
11
|
+
end
|
12
|
+
|
13
|
+
# @private
|
14
|
+
class TzOperationFilter < AbstractTzFilter
|
15
|
+
register :tz_operation
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prefixes
|
20
|
+
%i[o].freeze
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteraction
|
4
|
+
class Base
|
5
|
+
# @!method self.tz_public_key(*attributes, options = {})
|
6
|
+
# Creates accessors for the attributes and ensures that values passed to
|
7
|
+
# the attributes are Strings.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# tz_public_key :public_key
|
11
|
+
end
|
12
|
+
|
13
|
+
# @private
|
14
|
+
class TzPublicKeyFilter < AbstractTzFilter
|
15
|
+
register :tz_public_key
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prefixes
|
20
|
+
%i[edpk].freeze
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|