rubanok 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: []