jrf 0.1.11 → 0.1.12

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: edaeb729eecf63449c68fce92740acb8221885ff28a5ed26fe7bea32eb0a9bfa
4
- data.tar.gz: 30364ac5e6eee46506da8c4d3ff2d8a05f12cd91b2b5cd248a12e612ea333891
3
+ metadata.gz: ddf9bb5a12260eea615d0107dc7374dec2b5a3fe81c51791ea7e7ffea359d12f
4
+ data.tar.gz: d556b7d230185a9c397af45abaa08b912f485f3a1494bebdf86f2ef44be81c64
5
5
  SHA512:
6
- metadata.gz: 22e73015ffb398d376c3636f8a9e324c01bd56ae5dc1170b39a8ad5c600c10273fadec1de5385706798e3aff19449b446744e608f1437ca73113871c33aa9b1b
7
- data.tar.gz: 4c803ad64d65d6ae1d671426c2e81a4741ebcebd66ca4fb288574336e0a1088b8be2aa78f4235213ffc5794c92877410c88cbce7dae1f88bfb6369f6f37e3970
6
+ metadata.gz: e7642e5e7c50e9b4da7f28bf906bf432ee7c6d377839af2ff2b73d299c044e08566876bd3d33d5492abe9432b58f0871df2ebb9d4e7ec45ffe02a495fad1e2fc
7
+ data.tar.gz: '0629e81b1c9cf8070fb0a1fcbe409cf026bb62f72da9855d32fe9f253552de51a21f663b616abdc3b474dd705d9067512838fe5f0e33293f423636a5ea18167f'
@@ -59,6 +59,10 @@ module Jrf
59
59
  end
60
60
  end
61
61
 
62
+ define_reducer(:count_if) do |_ctx, condition, block: nil|
63
+ { value: condition, initial: 0, step: ->(acc, v) { v ? (acc + 1) : acc } }
64
+ end
65
+
62
66
  define_reducer(:min) do |_ctx, value, block: nil|
63
67
  { value: value, initial: nil, step: ->(acc, v) { v.nil? ? acc : (acc.nil? || v < acc ? v : acc) } }
64
68
  end
@@ -170,16 +174,22 @@ module Jrf
170
174
  @__jrf_current_stage.step_reduce(current_input, initial: initial, &block)
171
175
  end
172
176
 
173
- def map(&block)
177
+ def map(collection = nil, &block)
174
178
  raise ArgumentError, "map requires a block" unless block
175
179
 
176
- @__jrf_current_stage.step_map(:map, current_input, &block)
180
+ @__jrf_current_stage.step_map(:map, collection || current_input, &block)
177
181
  end
178
182
 
179
- def map_values(&block)
183
+ def map_values(collection = nil, &block)
180
184
  raise ArgumentError, "map_values requires a block" unless block
181
185
 
182
- @__jrf_current_stage.step_map(:map_values, current_input, &block)
186
+ @__jrf_current_stage.step_map(:map_values, collection || current_input, &block)
187
+ end
188
+
189
+ def apply(collection = nil, &block)
190
+ raise ArgumentError, "apply requires a block" unless block
191
+
192
+ @__jrf_current_stage.step_apply(collection || current_input, &block)
183
193
  end
184
194
 
185
195
  def group_by(key, &block)
data/lib/jrf/stage.rb CHANGED
@@ -113,6 +113,35 @@ module Jrf
113
113
  ReducerToken.new(idx)
114
114
  end
115
115
 
116
+ def step_apply(collection, &block)
117
+ raise TypeError, "apply expects Array, got #{collection.class}" unless collection.is_a?(Array)
118
+
119
+ apply_reducers = []
120
+ template = nil
121
+ results = []
122
+
123
+ collection.each do |v|
124
+ with_scoped_reducers(apply_reducers) do
125
+ result = @ctx.send(:__jrf_with_current_input, v) { block.call(v) }
126
+ template ||= result
127
+ results << result
128
+ end
129
+ end
130
+
131
+ if apply_reducers.any?
132
+ self.class.resolve_template(template, apply_reducers)
133
+ else
134
+ results.each_with_object([]) do |mapped, arr|
135
+ next if mapped.equal?(Control::DROPPED)
136
+ if mapped.is_a?(Control::Flat)
137
+ arr.concat(Array(mapped.value))
138
+ else
139
+ arr << mapped
140
+ end
141
+ end
142
+ end
143
+ end
144
+
116
145
  def step_group_by(key, &block)
117
146
  idx = @cursor
118
147
  map_reducer = (@reducers[idx] ||= MapReducer.new(:group_by, false))
data/lib/jrf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jrf
4
- VERSION = "0.1.11"
4
+ VERSION = "0.1.12"
5
5
  end
data/test/jrf_test.rb CHANGED
@@ -534,6 +534,23 @@ stdout, stderr, status = run_jrf('count(_["foo"])', input_with_nil)
534
534
  assert_success(status, stderr, "count(expr) ignores nil")
535
535
  assert_equal(%w[2], lines(stdout), "count(expr) ignores nil output")
536
536
 
537
+ # count_if
538
+ input_count_if = <<~NDJSON
539
+ {"x":1}
540
+ {"x":-2}
541
+ {"x":3}
542
+ {"x":-4}
543
+ {"x":5}
544
+ NDJSON
545
+
546
+ stdout, stderr, status = run_jrf('count_if(_["x"] > 0)', input_count_if)
547
+ assert_success(status, stderr, "count_if")
548
+ assert_equal(%w[3], lines(stdout), "count_if output")
549
+
550
+ stdout, stderr, status = run_jrf('[count_if(_["x"] > 0), count_if(_["x"] < 0)]', input_count_if)
551
+ assert_success(status, stderr, "count_if multiple")
552
+ assert_equal(["[3,2]"], lines(stdout), "count_if multiple output")
553
+
537
554
  input_all_nil = <<~NDJSON
538
555
  {"foo":null}
539
556
  {"bar":1}
@@ -855,6 +872,36 @@ stdout, stderr, status = run_jrf('map_values { |obj| map_values { |v| sum(v) } }
855
872
  assert_success(status, stderr, "nested map_values reducer binds to current target")
856
873
  assert_equal(['{"a":{"x":4,"y":6},"b":{"x":40,"y":60}}'], lines(stdout), "nested map_values reducer output")
857
874
 
875
+ # apply - aggregation
876
+ stdout, stderr, status = run_jrf('[apply { |x| sum(x["foo"]) }, _.length]', '[{"foo":1},{"foo":2}]' + "\n" + '[{"foo":10}]' + "\n")
877
+ assert_success(status, stderr, "apply with sum")
878
+ assert_equal(["[3,2]", "[10,1]"], lines(stdout), "apply with sum output")
879
+
880
+ # apply - passthrough
881
+ stdout, stderr, status = run_jrf('apply { |x| x["foo"] }', '[{"foo":1},{"foo":2}]' + "\n")
882
+ assert_success(status, stderr, "apply passthrough")
883
+ assert_equal(["[1,2]"], lines(stdout), "apply passthrough output")
884
+
885
+ # apply - percentile
886
+ stdout, stderr, status = run_jrf('apply { |x| percentile(x, 0.5) }', '[10,20,30]' + "\n")
887
+ assert_success(status, stderr, "apply with percentile")
888
+ assert_equal(["20"], lines(stdout), "apply with percentile output")
889
+
890
+ # apply with explicit collection inside map
891
+ stdout, stderr, status = run_jrf('map { |o| [apply(o["vals"]) { |x| sum(x) }, o["name"]] }', '[{"name":"a","vals":[1,2]},{"name":"b","vals":[10,20]}]' + "\n")
892
+ assert_success(status, stderr, "apply with explicit collection")
893
+ assert_equal(['[[3,"a"],[30,"b"]]'], lines(stdout), "apply with explicit collection output")
894
+
895
+ # map with explicit collection
896
+ stdout, stderr, status = run_jrf('map(_["items"]) { |x| x * 2 }', '{"items":[1,2,3]}' + "\n")
897
+ assert_success(status, stderr, "map with explicit collection")
898
+ assert_equal(["[2,4,6]"], lines(stdout), "map with explicit collection output")
899
+
900
+ # map_values with explicit collection
901
+ stdout, stderr, status = run_jrf('map_values(_["data"]) { |v| v * 10 }', '{"data":{"a":1,"b":2}}' + "\n")
902
+ assert_success(status, stderr, "map_values with explicit collection")
903
+ assert_equal(['{"a":10,"b":20}'], lines(stdout), "map_values with explicit collection output")
904
+
858
905
  input_gb = <<~NDJSON
859
906
  {"status":200,"path":"/a","latency":10}
860
907
  {"status":404,"path":"/b","latency":50}
@@ -976,6 +1023,30 @@ assert_equal([[["a", 1], ["b", 2]]], j.call([{"a" => 1, "b" => 2}]), "library ma
976
1023
  j = Jrf.new(proc { map { |k, v| sum(v + k.length) } })
977
1024
  assert_equal([[5, 7]], j.call([{"a" => 1, "b" => 2}, {"a" => 2, "b" => 3}]), "library map hash reduce")
978
1025
 
1026
+ # apply - aggregation
1027
+ j = Jrf.new(proc { [apply { |x| sum(x["foo"]) }, _.length] })
1028
+ assert_equal([[3, 2], [10, 1]], j.call([[{"foo" => 1}, {"foo" => 2}], [{"foo" => 10}]]), "library apply reducer")
1029
+
1030
+ # apply - passthrough
1031
+ j = Jrf.new(proc { apply { |x| x["foo"] } })
1032
+ assert_equal([[1, 2]], j.call([[{"foo" => 1}, {"foo" => 2}]]), "library apply passthrough")
1033
+
1034
+ # apply - percentile
1035
+ j = Jrf.new(proc { apply { |x| percentile(x, 0.5) } })
1036
+ assert_equal([20], j.call([[10, 20, 30]]), "library apply percentile")
1037
+
1038
+ # apply with explicit collection inside map
1039
+ j = Jrf.new(proc { map { |o| [apply(o["vals"]) { |x| sum(x) }, o["name"]] } })
1040
+ assert_equal([[[3, "a"], [30, "b"]]], j.call([[{"name" => "a", "vals" => [1, 2]}, {"name" => "b", "vals" => [10, 20]}]]), "library apply explicit collection")
1041
+
1042
+ # map with explicit collection
1043
+ j = Jrf.new(proc { map(_["items"]) { |x| x * 2 } })
1044
+ assert_equal([[2, 4, 6]], j.call([{"items" => [1, 2, 3]}]), "library map explicit collection")
1045
+
1046
+ # map_values with explicit collection
1047
+ j = Jrf.new(proc { map_values(_["data"]) { |v| v * 10 } })
1048
+ assert_equal([{"a" => 10, "b" => 20}], j.call([{"data" => {"a" => 1, "b" => 2}}]), "library map_values explicit collection")
1049
+
979
1050
  # group_by
980
1051
  j = Jrf.new(proc { group_by(_["k"]) { count() } })
981
1052
  assert_equal([{"x" => 2, "y" => 1}], j.call([{"k" => "x"}, {"k" => "x"}, {"k" => "y"}]), "library group_by")
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jrf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - kazuho
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-03-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: oj
@@ -49,11 +48,9 @@ files:
49
48
  - lib/jrf/stage.rb
50
49
  - lib/jrf/version.rb
51
50
  - test/jrf_test.rb
52
- homepage:
53
51
  licenses:
54
52
  - MIT
55
53
  metadata: {}
56
- post_install_message:
57
54
  rdoc_options: []
58
55
  require_paths:
59
56
  - lib
@@ -68,8 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
65
  - !ruby/object:Gem::Version
69
66
  version: '0'
70
67
  requirements: []
71
- rubygems_version: 3.0.3.1
72
- signing_key:
68
+ rubygems_version: 4.0.3
73
69
  specification_version: 4
74
70
  summary: JSON filter with the power and speed of Ruby
75
71
  test_files: []