rubanok 0.4.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90f6ca9dfd61a6f143eff1f3ab3c2d7e41502c992879af785dcf414af15249fd
4
- data.tar.gz: 8807cbb2a680e9fbc739a9f0214fb4753e24ee55e69da72d9b45c7f121900dd9
3
+ metadata.gz: 8233d2946a61205ae18864a6304de48bf1d89621c989e8e364ce6b7f55cce3b6
4
+ data.tar.gz: 5ee328fb4f857065e11750dc2a9a8f169c7eebd9120d86c0617594929ab7e1d5
5
5
  SHA512:
6
- metadata.gz: 2e015d7c3c517e42e5fe42037035db950cc87f9bd0099b38580c03ad156c36d0133681bd659451e8bdb58f15254799ce8d7b3158a1dc998210e3a425867a521d
7
- data.tar.gz: 6c22e9a876e86f144726e8dbbe79b42f9d3052feb6f9c31688f7259872a5eed1e5ac66b031b890e0d1b4eceba7d3903331a073f2e13321b9f3d45c9fe53229d2
6
+ metadata.gz: 3ca8ec88b1f4f86c30834c429cdc1acfe98a4e6ce1e19bf707acf9178f8a46c729c65e5a4549190ebd3781150362d396f72cd163441df3174b9adb4ddc876af9
7
+ data.tar.gz: cf3bd84216aa32ddf4dc2150213659ac70f52fef84dfe2842cdd7b80acc362042196e9385fa42d3dd84dae4b26ebea0e84eb0232692035b55c09a5b99e0c21ee
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.5.0 (2023-12-04)
6
+
7
+ - Add nested processors support. ([@palkan][])
8
+
5
9
  ## 0.4.0 (2021-03-05)
6
10
 
7
11
  - Ruby 3.0 compatibility. ([@palkan][])
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018-2020 Vladimir Dementyev
3
+ Copyright (c) 2018-2024 Vladimir Dementyev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -53,8 +53,8 @@ end
53
53
 
54
54
  Requirements:
55
55
 
56
- - Ruby ~> 2.5
57
- - (optional\*) Rails >= 5.2 (Rails 4.2 should work but we don't test against it anymore)
56
+ - Ruby ~> 2.7
57
+ - (optional\*) Rails >= 6.0 (see older releases for Rails <6 support)
58
58
 
59
59
  \* This gem has no dependency on Rails.
60
60
 
@@ -155,6 +155,28 @@ If in example above you will call `CourseSessionsProcessor.call(CourseSession, f
155
155
 
156
156
  **NOTE:** Rubanok only matches exact values; more complex matching could be added in the future.
157
157
 
158
+ ### Nested processors
159
+
160
+ You can use the `.process` method to define sub-processors (or nested processors). It's useful when you use nested params, for example:
161
+
162
+ ```ruby
163
+ class CourseSessionsProcessor < Rubanok::Processor
164
+ process :filter do
165
+ match :status do
166
+ having "draft" do
167
+ raw.where(draft: true)
168
+ end
169
+
170
+ having "deleted" do
171
+ raw.where.not(deleted_at: nil)
172
+ end
173
+ end
174
+
175
+ # You can also use .map or even .process here
176
+ end
177
+ end
178
+ ```
179
+
158
180
  ### Default transformation
159
181
 
160
182
  Sometimes it's useful to perform some transformations before **any** rule is activated.
@@ -40,10 +40,6 @@ module Rubanok
40
40
  add_rule rule
41
41
  end
42
42
  end
43
-
44
- def self.included(base)
45
- base.extend ClassMethods
46
- end
47
43
  end
48
44
  end
49
45
  end
@@ -26,7 +26,7 @@ module Rubanok
26
26
  super(fields, activate_on: activate_on, activate_always: activate_always)
27
27
  @id = id
28
28
  @block = block
29
- @values = Hash[fields.take(values.size).zip(values)].freeze
29
+ @values = fields.take(values.size).zip(values).to_h.freeze
30
30
  @fields = (fields - @values.keys).freeze
31
31
  end
32
32
 
@@ -34,7 +34,7 @@ module Rubanok
34
34
  values.all? { |key, matcher| params.key?(key) && (matcher == params[key]) }
35
35
  end
36
36
 
37
- alias to_method_name id
37
+ alias_method :to_method_name, :id
38
38
  end
39
39
 
40
40
  attr_reader :clauses
@@ -73,7 +73,7 @@ module Rubanok
73
73
  rule.instance_eval(&block)
74
74
 
75
75
  define_method(rule.to_method_name) do |params = {}|
76
- params ||= {} if params.nil?
76
+ params ||= {}
77
77
 
78
78
  clause = rule.matching_clause(params)
79
79
 
@@ -92,10 +92,6 @@ module Rubanok
92
92
  end
93
93
  end
94
94
 
95
- def self.included(base)
96
- base.extend ClassMethods
97
- end
98
-
99
95
  def default_match_handler(rule, params, fail_when_no_matches)
100
96
  fail_when_no_matches = Rubanok.fail_when_no_matches if fail_when_no_matches.nil?
101
97
  return raw unless fail_when_no_matches
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubanok
4
+ module DSL
5
+ # Adds `.process` method to Processor to define a nested processor:
6
+ #
7
+ # process :filter do
8
+ # map :status do |status:|
9
+ # raw.where(status:)
10
+ # end
11
+ #
12
+ module Process
13
+ class Rule < Rubanok::Rule
14
+ METHOD_PREFIX = "__process"
15
+
16
+ def initialize(...)
17
+ super
18
+ raise ArgumentError, "Nested processor requires exactly one field" if fields.size != 1
19
+ @field = fields.first
20
+ end
21
+
22
+ def define_processor(superclass, &block)
23
+ @processor = Class.new(superclass, &block)
24
+ end
25
+
26
+ def process(input, params)
27
+ return input if params.nil?
28
+
29
+ subparams = fetch_value(params, field)
30
+ return input if subparams == UNDEFINED
31
+
32
+ return input unless subparams.respond_to?(:transform_keys)
33
+
34
+ # @type var subparams : params
35
+ processor.call(input, subparams)
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :processor, :field
41
+
42
+ def build_method_name
43
+ "#{METHOD_PREFIX}#{super}"
44
+ end
45
+ end
46
+
47
+ module ClassMethods
48
+ def process(field, superclass: ::Rubanok::Processor, activate_on: [field], activate_always: false, ignore_empty_values: Rubanok.ignore_empty_values, filter_with: nil, &block)
49
+ filter = filter_with
50
+
51
+ if filter.is_a?(Symbol)
52
+ respond_to?(filter) || raise(
53
+ ArgumentError,
54
+ "Unknown class method #{filter} for #{self}. " \
55
+ "Make sure that a filter method is defined before the call to .map."
56
+ )
57
+ filter = method(filter)
58
+ end
59
+
60
+ rule = Rule.new([field], activate_on: activate_on, activate_always: activate_always, ignore_empty_values: ignore_empty_values, filter_with: filter)
61
+ rule.define_processor(superclass, &block)
62
+
63
+ define_method(rule.to_method_name) do |params = {}|
64
+ rule.process(raw, params)
65
+ end
66
+
67
+ add_rule rule
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -6,6 +6,7 @@ require "rubanok/rule"
6
6
 
7
7
  require "rubanok/dsl/mapping"
8
8
  require "rubanok/dsl/matching"
9
+ require "rubanok/dsl/process"
9
10
 
10
11
  module Rubanok
11
12
  # Base class for processors (_planes_)
@@ -29,8 +30,12 @@ module Rubanok
29
30
  #
30
31
  # You can access the input data via `raw` method.
31
32
  class Processor
33
+ extend DSL::Matching::ClassMethods
32
34
  include DSL::Matching
35
+ extend DSL::Mapping::ClassMethods
33
36
  include DSL::Mapping
37
+ extend DSL::Process::ClassMethods
38
+ include DSL::Process
34
39
 
35
40
  UNDEFINED = Object.new
36
41
 
@@ -106,8 +111,8 @@ module Rubanok
106
111
 
107
112
  attr_accessor :input, :prepared
108
113
 
109
- alias raw input
110
- alias prepared? prepared
114
+ alias_method :raw, :input
115
+ alias_method :prepared?, :prepared
111
116
 
112
117
  def apply_rule!(rule, params)
113
118
  method_name, data = rule.to_method_name, rule.project(params)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubanok
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -1,6 +1,6 @@
1
1
  module Rubanok
2
2
  module DSL
3
- module Mapping : Processor
3
+ module Mapping : _Processor
4
4
  class Rule < Rubanok::Rule
5
5
  METHOD_PREFIX: String
6
6
 
@@ -11,8 +11,6 @@ module Rubanok
11
11
  module ClassMethods : Module, _RulesAdding
12
12
  def map: (*field fields, ?activate_on: (field | Array[field]), ?activate_always: bool, ?ignore_empty_values: bool, ?filter_with: Symbol) { () -> input } -> void
13
13
  end
14
-
15
- def self.included: (singleton(Processor) base) -> void
16
14
  end
17
15
  end
18
16
  end
@@ -3,7 +3,7 @@ module Rubanok
3
3
  end
4
4
 
5
5
  module DSL
6
- module Matching : Processor
6
+ module Matching : _Processor
7
7
  class Rule < Rubanok::Rule
8
8
  METHOD_PREFIX: String
9
9
  @method_name: String
@@ -32,13 +32,12 @@ module Rubanok
32
32
  def build_method_name: () -> String
33
33
  end
34
34
 
35
- module ClassMethods : Module, _RulesAdding, Matching
35
+ def default_match_handler: (Rule rule, hash params, bool? fail_when_no_matches) -> void
36
+
37
+ module ClassMethods : Module, _RulesAdding
36
38
  def match: (*field fields, ?activate_on: field | Array[field], ?activate_always: bool, ?fail_when_no_matches: bool?) { (Rule) -> void } -> void
39
+ def define_method: (String | Symbol) ?{ () [self: Rubanok::Processor] -> void } -> Symbol
37
40
  end
38
-
39
- def self.included: (singleton(Processor) base) -> void
40
-
41
- def default_match_handler: (Rule rule, hash params, bool? fail_when_no_matches) -> void
42
41
  end
43
42
  end
44
43
  end
@@ -0,0 +1,23 @@
1
+ module Rubanok
2
+ module DSL
3
+ module Process : _Processor
4
+ class Rule < Rubanok::Rule
5
+ METHOD_PREFIX: String
6
+
7
+ attr_reader field: field
8
+ attr_reader processor: singleton(Processor)
9
+
10
+ %a{rbs:test:skip} def define_processor: (singleton(Processor)) { () -> void } -> void
11
+ def process: (input, params | nil) -> input
12
+
13
+ private
14
+ def build_method_name: () -> String
15
+ end
16
+
17
+ module ClassMethods : Module, _RulesAdding
18
+ %a{rbs:test:skip} def process: (field, superclass: singleton(Processor), ?activate_on: (field | Array[field]), ?activate_always: bool, ?ignore_empty_values: bool, ?filter_with: Symbol) { () -> input } -> void
19
+ def define_method: (String | Symbol) ?{ () [self: Rubanok::Processor] -> void } -> Symbol
20
+ end
21
+ end
22
+ end
23
+ end
@@ -11,11 +11,20 @@ module Rubanok
11
11
  def add_rule: (Rule rule) -> void
12
12
  end
13
13
 
14
+ interface _Processor
15
+ def raw: () -> input
16
+ end
17
+
14
18
  class Processor
19
+ include DSL::Matching
15
20
  extend DSL::Matching::ClassMethods
16
21
 
22
+ include DSL::Mapping
17
23
  extend DSL::Mapping::ClassMethods
18
24
 
25
+ include DSL::Process
26
+ extend DSL::Process::ClassMethods
27
+
19
28
  extend _RulesAdding
20
29
 
21
30
  UNDEFINED: Object
data/sig/typeprof.rb CHANGED
@@ -10,6 +10,16 @@ processor = Class.new(Rubanok::Processor) do
10
10
  raw
11
11
  end
12
12
 
13
+ process :filter do
14
+ map :status do |status:|
15
+ raw
16
+ end
17
+
18
+ map :name do |name:|
19
+ raw
20
+ end
21
+ end
22
+
13
23
  match :sort_by, :sort, activate_on: :sort_by do
14
24
  having "status", "asc" do
15
25
  raw
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubanok
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-05 00:00:00.000000000 Z
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.2'
19
+ version: '6.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.2'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: actionview
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.2'
33
+ version: '6.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5.2'
40
+ version: '6.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +107,7 @@ files:
107
107
  - lib/rubanok.rb
108
108
  - lib/rubanok/dsl/mapping.rb
109
109
  - lib/rubanok/dsl/matching.rb
110
+ - lib/rubanok/dsl/process.rb
110
111
  - lib/rubanok/processor.rb
111
112
  - lib/rubanok/rails/controller.rb
112
113
  - lib/rubanok/railtie.rb
@@ -116,6 +117,7 @@ files:
116
117
  - sig/rubanok.rbs
117
118
  - sig/rubanok/dsl/mapping.rbs
118
119
  - sig/rubanok/dsl/matching.rbs
120
+ - sig/rubanok/dsl/process.rbs
119
121
  - sig/rubanok/processor.rbs
120
122
  - sig/rubanok/rule.rbs
121
123
  - sig/rubanok/version.rbs
@@ -129,7 +131,7 @@ metadata:
129
131
  documentation_uri: http://github.com/palkan/rubanok
130
132
  homepage_uri: http://github.com/palkan/rubanok
131
133
  source_code_uri: http://github.com/palkan/rubanok
132
- post_install_message:
134
+ post_install_message:
133
135
  rdoc_options: []
134
136
  require_paths:
135
137
  - lib
@@ -137,15 +139,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
139
  requirements:
138
140
  - - ">="
139
141
  - !ruby/object:Gem::Version
140
- version: 2.5.0
142
+ version: 2.7.0
141
143
  required_rubygems_version: !ruby/object:Gem::Requirement
142
144
  requirements:
143
145
  - - ">="
144
146
  - !ruby/object:Gem::Version
145
147
  version: '0'
146
148
  requirements: []
147
- rubygems_version: 3.0.6
148
- signing_key:
149
+ rubygems_version: 3.4.20
150
+ signing_key:
149
151
  specification_version: 4
150
152
  summary: Parameters-based transformation DSL
151
153
  test_files: []