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.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +15 -0
  3. data/.gitignore +3 -0
  4. data/.travis.yml +14 -10
  5. data/CHANGELOG.md +22 -1
  6. data/Gemfile +5 -18
  7. data/README.md +3 -5
  8. data/Rakefile +1 -0
  9. data/lib/transproc.rb +3 -4
  10. data/lib/transproc/all.rb +2 -0
  11. data/lib/transproc/array.rb +5 -3
  12. data/lib/transproc/array/combine.rb +2 -0
  13. data/lib/transproc/class.rb +2 -0
  14. data/lib/transproc/coercions.rb +2 -0
  15. data/lib/transproc/compiler.rb +45 -0
  16. data/lib/transproc/composer.rb +2 -0
  17. data/lib/transproc/composite.rb +2 -0
  18. data/lib/transproc/conditional.rb +2 -0
  19. data/lib/transproc/constants.rb +5 -0
  20. data/lib/transproc/error.rb +2 -0
  21. data/lib/transproc/function.rb +2 -0
  22. data/lib/transproc/functions.rb +2 -0
  23. data/lib/transproc/hash.rb +83 -34
  24. data/lib/transproc/proc.rb +2 -0
  25. data/lib/transproc/recursion.rb +2 -0
  26. data/lib/transproc/registry.rb +1 -0
  27. data/lib/transproc/store.rb +1 -0
  28. data/lib/transproc/support/deprecations.rb +2 -0
  29. data/lib/transproc/transformer.rb +7 -1
  30. data/lib/transproc/transformer/class_interface.rb +31 -65
  31. data/lib/transproc/transformer/deprecated/class_interface.rb +80 -0
  32. data/lib/transproc/transformer/dsl.rb +51 -0
  33. data/lib/transproc/version.rb +3 -1
  34. data/spec/spec_helper.rb +15 -11
  35. data/spec/unit/array/combine_spec.rb +3 -1
  36. data/spec/unit/array_transformations_spec.rb +1 -1
  37. data/spec/unit/class_transformations_spec.rb +9 -6
  38. data/spec/unit/coercions_spec.rb +1 -1
  39. data/spec/unit/composer_spec.rb +1 -1
  40. data/spec/unit/conditional_spec.rb +1 -1
  41. data/spec/unit/function_not_found_error_spec.rb +1 -1
  42. data/spec/unit/function_spec.rb +1 -1
  43. data/spec/unit/hash_transformations_spec.rb +12 -1
  44. data/spec/unit/proc_transformations_spec.rb +3 -1
  45. data/spec/unit/recursion_spec.rb +1 -1
  46. data/spec/unit/registry_spec.rb +1 -1
  47. data/spec/unit/store_spec.rb +2 -1
  48. data/spec/unit/transformer/class_interface_spec.rb +364 -0
  49. data/spec/unit/transformer/dsl_spec.rb +15 -0
  50. data/spec/unit/transformer/instance_methods_spec.rb +25 -0
  51. data/spec/unit/transformer_spec.rb +128 -40
  52. data/spec/unit/transproc_spec.rb +1 -1
  53. data/transproc.gemspec +1 -5
  54. metadata +16 -54
  55. data/.rubocop.yml +0 -66
  56. data/.rubocop_todo.yml +0 -11
  57. data/rakelib/mutant.rake +0 -16
  58. data/rakelib/rubocop.rake +0 -18
  59. data/spec/support/mutant.rb +0 -10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Transproc
2
4
  # Transformation functions for Procs
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'transproc/conditional'
2
4
 
3
5
  module Transproc
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Transproc
4
5
  # Container to define transproc functions in, and access them via `[]` method
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Transproc
4
5
  # Immutable collection of named procedures from external modules
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Transproc
2
4
  module Deprecations
3
5
  def self.announce(name, msg)
@@ -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
- self.class.transproc.call(input)
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 private
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(Transformer)
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 = ::Transproc::Undefined)
49
- if container == ::Transproc::Undefined
50
- ensure_container_presence!
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 define(&block)
78
- return transproc unless block_given?
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
- Class.new(self).tap { |klass| klass.instance_eval(&block) }.transproc
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Transproc
2
- VERSION = '1.0.2'.freeze
4
+ VERSION = '1.1.0'.freeze
3
5
  end
@@ -1,19 +1,23 @@
1
- if RUBY_ENGINE == 'ruby' && RUBY_VERSION == '2.3.1'
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter '/spec/'
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
- end
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,4 +1,6 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
2
4
 
3
5
  describe Transproc::ArrayTransformations do
4
6
  describe '.combine' do
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Transproc::ArrayTransformations do
4
4
  let(:hashes) { Transproc::HashTransformations }
@@ -1,9 +1,11 @@
1
- require 'spec_helper'
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 Anima.new(:name, :age)
26
+ include Dry::Equalizer.new(:name, :age)
25
27
 
26
- attr_reader :test
28
+ attr_reader :name, :age, :test
27
29
 
28
- def initialize(*args)
29
- super
30
+ def initialize(name:, age:)
31
+ @name = name
32
+ @age = age
30
33
  @test = true
31
34
  end
32
35
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Transproc::Coercions do
4
4
  describe '.identity' do
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Transproc::Composer do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Transproc::Conditional do
4
4
  describe '.not' do
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Transproc::FunctionNotFoundError do
4
4
  it 'complains that the function not registered' do