transproc 1.0.2 → 1.1.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.
- checksums.yaml +5 -5
- data/.codeclimate.yml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +14 -10
- data/CHANGELOG.md +22 -1
- data/Gemfile +5 -18
- data/README.md +3 -5
- data/Rakefile +1 -0
- data/lib/transproc.rb +3 -4
- data/lib/transproc/all.rb +2 -0
- data/lib/transproc/array.rb +5 -3
- data/lib/transproc/array/combine.rb +2 -0
- data/lib/transproc/class.rb +2 -0
- data/lib/transproc/coercions.rb +2 -0
- data/lib/transproc/compiler.rb +45 -0
- data/lib/transproc/composer.rb +2 -0
- data/lib/transproc/composite.rb +2 -0
- data/lib/transproc/conditional.rb +2 -0
- data/lib/transproc/constants.rb +5 -0
- data/lib/transproc/error.rb +2 -0
- data/lib/transproc/function.rb +2 -0
- data/lib/transproc/functions.rb +2 -0
- data/lib/transproc/hash.rb +83 -34
- data/lib/transproc/proc.rb +2 -0
- data/lib/transproc/recursion.rb +2 -0
- data/lib/transproc/registry.rb +1 -0
- data/lib/transproc/store.rb +1 -0
- data/lib/transproc/support/deprecations.rb +2 -0
- data/lib/transproc/transformer.rb +7 -1
- data/lib/transproc/transformer/class_interface.rb +31 -65
- data/lib/transproc/transformer/deprecated/class_interface.rb +80 -0
- data/lib/transproc/transformer/dsl.rb +51 -0
- data/lib/transproc/version.rb +3 -1
- data/spec/spec_helper.rb +15 -11
- data/spec/unit/array/combine_spec.rb +3 -1
- data/spec/unit/array_transformations_spec.rb +1 -1
- data/spec/unit/class_transformations_spec.rb +9 -6
- data/spec/unit/coercions_spec.rb +1 -1
- data/spec/unit/composer_spec.rb +1 -1
- data/spec/unit/conditional_spec.rb +1 -1
- data/spec/unit/function_not_found_error_spec.rb +1 -1
- data/spec/unit/function_spec.rb +1 -1
- data/spec/unit/hash_transformations_spec.rb +12 -1
- data/spec/unit/proc_transformations_spec.rb +3 -1
- data/spec/unit/recursion_spec.rb +1 -1
- data/spec/unit/registry_spec.rb +1 -1
- data/spec/unit/store_spec.rb +2 -1
- data/spec/unit/transformer/class_interface_spec.rb +364 -0
- data/spec/unit/transformer/dsl_spec.rb +15 -0
- data/spec/unit/transformer/instance_methods_spec.rb +25 -0
- data/spec/unit/transformer_spec.rb +128 -40
- data/spec/unit/transproc_spec.rb +1 -1
- data/transproc.gemspec +1 -5
- metadata +16 -54
- data/.rubocop.yml +0 -66
- data/.rubocop_todo.yml +0 -11
- data/rakelib/mutant.rake +0 -16
- data/rakelib/rubocop.rake +0 -18
- data/spec/support/mutant.rb +0 -10
data/lib/transproc/proc.rb
CHANGED
data/lib/transproc/recursion.rb
CHANGED
data/lib/transproc/registry.rb
CHANGED
data/lib/transproc/store.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'transproc/transformer/class_interface'
|
4
|
+
require 'transproc/transformer/deprecated/class_interface'
|
2
5
|
|
3
6
|
module Transproc
|
4
7
|
# Transfomer class for defining transprocs with a class DSL.
|
@@ -45,6 +48,9 @@ module Transproc
|
|
45
48
|
# @api public
|
46
49
|
class Transformer
|
47
50
|
extend ClassInterface
|
51
|
+
extend Deprecated::ClassInterface
|
52
|
+
|
53
|
+
attr_reader :transproc
|
48
54
|
|
49
55
|
# Execute the transformation pipeline with the given input.
|
50
56
|
#
|
@@ -63,7 +69,7 @@ module Transproc
|
|
63
69
|
#
|
64
70
|
# @api public
|
65
71
|
def call(input)
|
66
|
-
|
72
|
+
transproc.call(input)
|
67
73
|
end
|
68
74
|
end
|
69
75
|
end
|
@@ -1,7 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'transproc/transformer/dsl'
|
4
|
+
|
1
5
|
module Transproc
|
2
6
|
class Transformer
|
3
|
-
# @api
|
7
|
+
# @api public
|
4
8
|
module ClassInterface
|
9
|
+
# @api private
|
10
|
+
attr_reader :dsl
|
11
|
+
|
5
12
|
# Return a base Transproc::Transformer class with the
|
6
13
|
# container configured to the passed argument.
|
7
14
|
#
|
@@ -17,14 +24,18 @@ module Transproc
|
|
17
24
|
#
|
18
25
|
# @api public
|
19
26
|
def [](container)
|
20
|
-
klass = Class.new(
|
27
|
+
klass = Class.new(self)
|
21
28
|
klass.container(container)
|
22
29
|
klass
|
23
30
|
end
|
24
31
|
|
25
32
|
# @api private
|
26
33
|
def inherited(subclass)
|
34
|
+
super
|
35
|
+
|
27
36
|
subclass.container(@container) if defined?(@container)
|
37
|
+
|
38
|
+
subclass.instance_variable_set('@dsl', dsl.dup) if dsl
|
28
39
|
end
|
29
40
|
|
30
41
|
# Get or set the container to resolve transprocs from.
|
@@ -45,41 +56,32 @@ module Transproc
|
|
45
56
|
# @return [Transproc::Registry]
|
46
57
|
#
|
47
58
|
# @api private
|
48
|
-
def container(container =
|
49
|
-
if container
|
50
|
-
|
51
|
-
@container
|
59
|
+
def container(container = Undefined)
|
60
|
+
if container.equal?(Undefined)
|
61
|
+
@container ||= Module.new.extend(Transproc::Registry)
|
52
62
|
else
|
53
63
|
@container = container
|
54
64
|
end
|
55
65
|
end
|
56
66
|
|
57
|
-
# Define an anonymous transproc derived from given Transformer
|
58
|
-
# Evaluates block with transformations and returns initialized transproc.
|
59
|
-
# Does not mutate original Transformer
|
60
|
-
#
|
61
|
-
# @example
|
62
|
-
#
|
63
|
-
# class MyTransformer < Transproc::Transformer[MyContainer]
|
64
|
-
# end
|
65
|
-
#
|
66
|
-
# transproc = MyTransformer.define do
|
67
|
-
# map_values t(:to_string)
|
68
|
-
# end
|
69
|
-
# transproc.call(a: 1, b: 2)
|
70
|
-
# # => {a: '1', b: '2'}
|
71
|
-
#
|
72
|
-
# @yield Block allowing to define transformations. The same as class level DSL
|
73
|
-
#
|
74
|
-
# @return [Function] Composed transproc
|
75
|
-
#
|
76
67
|
# @api public
|
77
|
-
def
|
78
|
-
|
68
|
+
def import(*args)
|
69
|
+
container.import(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api public
|
73
|
+
def define!(&block)
|
74
|
+
@dsl ||= DSL.new(container)
|
75
|
+
@dsl.instance_eval(&block)
|
76
|
+
self
|
77
|
+
end
|
79
78
|
|
80
|
-
|
79
|
+
# @api public
|
80
|
+
def new(*args)
|
81
|
+
super(*args).tap do |transformer|
|
82
|
+
transformer.instance_variable_set('@transproc', dsl.(transformer)) if dsl
|
83
|
+
end
|
81
84
|
end
|
82
|
-
alias build define
|
83
85
|
|
84
86
|
# Get a transformation from the container,
|
85
87
|
# without adding it to the transformation pipeline
|
@@ -105,42 +107,6 @@ module Transproc
|
|
105
107
|
def t(fn, *args)
|
106
108
|
container[fn, *args]
|
107
109
|
end
|
108
|
-
|
109
|
-
# @api private
|
110
|
-
def method_missing(method, *args, &block)
|
111
|
-
if container.contain?(method)
|
112
|
-
args.push(define(&block)) if block_given?
|
113
|
-
transformations << t(method, *args)
|
114
|
-
else
|
115
|
-
super
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# @api private
|
120
|
-
def respond_to_missing?(method, _include_private = false)
|
121
|
-
container.contain?(method) || super
|
122
|
-
end
|
123
|
-
|
124
|
-
# @api private
|
125
|
-
def transproc
|
126
|
-
transformations.reduce(:>>)
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
# An array containing the transformation pipeline
|
132
|
-
#
|
133
|
-
# @api private
|
134
|
-
def transformations
|
135
|
-
@transformations ||= []
|
136
|
-
end
|
137
|
-
|
138
|
-
# @api private
|
139
|
-
def ensure_container_presence!
|
140
|
-
return if defined?(@container)
|
141
|
-
raise ArgumentError, 'Transformer function registry is empty. '\
|
142
|
-
'Provide your registry via Transproc::Transformer[YourRegistry]'
|
143
|
-
end
|
144
110
|
end
|
145
111
|
end
|
146
112
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Transproc
|
4
|
+
class Transformer
|
5
|
+
module Deprecated
|
6
|
+
# @api public
|
7
|
+
module ClassInterface
|
8
|
+
# @api public
|
9
|
+
def new(*args)
|
10
|
+
super(*args).tap do |transformer|
|
11
|
+
transformer.instance_variable_set('@transproc', transproc) if transformations.any?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def inherited(subclass)
|
17
|
+
super
|
18
|
+
|
19
|
+
if transformations.any?
|
20
|
+
subclass.instance_variable_set('@transformations', transformations.dup)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Define an anonymous transproc derived from given Transformer
|
25
|
+
# Evaluates block with transformations and returns initialized transproc.
|
26
|
+
# Does not mutate original Transformer
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
#
|
30
|
+
# class MyTransformer < Transproc::Transformer[MyContainer]
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# transproc = MyTransformer.define do
|
34
|
+
# map_values t(:to_string)
|
35
|
+
# end
|
36
|
+
# transproc.call(a: 1, b: 2)
|
37
|
+
# # => {a: '1', b: '2'}
|
38
|
+
#
|
39
|
+
# @yield Block allowing to define transformations. The same as class level DSL
|
40
|
+
#
|
41
|
+
# @return [Function] Composed transproc
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
def define(&block)
|
45
|
+
return transproc unless block_given?
|
46
|
+
|
47
|
+
Class.new(Transformer[container]).tap { |klass| klass.instance_eval(&block) }.transproc
|
48
|
+
end
|
49
|
+
alias build define
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def method_missing(method, *args, &block)
|
53
|
+
super unless container.contain?(method)
|
54
|
+
func = block ? t(method, *args, define(&block)) : t(method, *args)
|
55
|
+
transformations << func
|
56
|
+
func
|
57
|
+
end
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
def respond_to_missing?(method, _include_private = false)
|
61
|
+
super || container.contain?(method)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def transproc
|
66
|
+
transformations.reduce(:>>)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# An array containing the transformation pipeline
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def transformations
|
75
|
+
@transformations ||= []
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'transproc/compiler'
|
4
|
+
|
5
|
+
module Transproc
|
6
|
+
class Transformer
|
7
|
+
# @api public
|
8
|
+
class DSL
|
9
|
+
# @api private
|
10
|
+
attr_reader :container
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
attr_reader :ast
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def initialize(container, ast: [], &block)
|
17
|
+
@container = container
|
18
|
+
@ast = ast
|
19
|
+
instance_eval(&block) if block
|
20
|
+
end
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
def dup
|
24
|
+
self.class.new(container, ast: ast.dup)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def call(transformer)
|
29
|
+
Compiler.new(container, transformer).(ast)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def node(&block)
|
36
|
+
[:t, self.class.new(container, &block).ast]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def respond_to_missing?(method, _include_private = false)
|
41
|
+
super || container.contain?(method)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def method_missing(meth, *args, &block)
|
46
|
+
arg_nodes = *args.map { |a| [:arg, a] }
|
47
|
+
ast << [:fn, (block ? [meth, [*arg_nodes, node(&block)]] : [meth, arg_nodes])]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/transproc/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
|
4
|
+
require 'yaml'
|
5
|
+
rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
|
6
|
+
latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
|
7
|
+
|
8
|
+
if RUBY_VERSION == latest_mri
|
9
|
+
require 'simplecov'
|
10
|
+
SimpleCov.start do
|
11
|
+
add_filter '/spec/'
|
12
|
+
end
|
5
13
|
end
|
6
14
|
end
|
7
15
|
|
8
|
-
require 'equalizer'
|
9
|
-
require 'anima'
|
10
|
-
require 'ostruct'
|
11
|
-
require 'transproc/all'
|
12
|
-
|
13
16
|
begin
|
14
17
|
require 'byebug'
|
15
|
-
rescue LoadError
|
16
|
-
|
18
|
+
rescue LoadError;end
|
19
|
+
|
20
|
+
require 'transproc/all'
|
17
21
|
|
18
22
|
root = Pathname(__FILE__).dirname
|
19
23
|
Dir[root.join('support/*.rb').to_s].each { |f| require f }
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/equalizer'
|
2
4
|
|
3
5
|
describe Transproc::ClassTransformations do
|
4
6
|
describe '.constructor_inject' do
|
5
7
|
let(:klass) do
|
6
|
-
Struct.new(:name, :age) { include Equalizer.new(:name, :age) }
|
8
|
+
Struct.new(:name, :age) { include Dry::Equalizer.new(:name, :age) }
|
7
9
|
end
|
8
10
|
|
9
11
|
it 'returns a new object initialized with the given arguments' do
|
@@ -21,12 +23,13 @@ describe Transproc::ClassTransformations do
|
|
21
23
|
describe '.set_ivars' do
|
22
24
|
let(:klass) do
|
23
25
|
Class.new do
|
24
|
-
include
|
26
|
+
include Dry::Equalizer.new(:name, :age)
|
25
27
|
|
26
|
-
attr_reader :test
|
28
|
+
attr_reader :name, :age, :test
|
27
29
|
|
28
|
-
def initialize(
|
29
|
-
|
30
|
+
def initialize(name:, age:)
|
31
|
+
@name = name
|
32
|
+
@age = age
|
30
33
|
@test = true
|
31
34
|
end
|
32
35
|
end
|
data/spec/unit/coercions_spec.rb
CHANGED
data/spec/unit/composer_spec.rb
CHANGED