flex-cartesian 0.1.9 → 0.2

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -2
  3. data/lib/flex-cartesian.rb +41 -12
  4. metadata +19 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b26211b52fac8e2a26ff5408d422e6ae328aefbd67d0a18ac07ef0404006c05
4
- data.tar.gz: cf406e24632a26605b5002e91ddfdf63bddaeb0a361d2dbbab76f5514bfdec88
3
+ metadata.gz: 4b34c40aea1692a248f2f4ee506b8b7a5a66a8257f90b1f74a7613897f8047c4
4
+ data.tar.gz: 3fb4c691a65ebcda1f9606368f436ba1ebee56749dee9e27d04296884cfef26e
5
5
  SHA512:
6
- metadata.gz: 2cb31e4b65dba494aeac390ad1baee384c5eca90aeb67363cb374db4ba0c1e4b4d4f4dc6acac088642a751e9d7d4ee996b98c99abf49fdc98c615981c5c12663
7
- data.tar.gz: 2b9c27d532a24430cbd21508d91d02d2f29172d9069eab75a8af5c60a2fb25936ff014de5ffc6c5a7df29e08d07de1b7272aefb6edbc907f60a96ae1e1520236
6
+ metadata.gz: 455053108bada48ae9b224879069cfe6e43fca419391e194f5b90dbaece0523ab7810eb471e1768814c17bc61f4952171493fb5c38283473d7798039f6b8b8dd
7
+ data.tar.gz: 63ebb02a0fb22162b67d17caf483ab2abc3499e9d072ddec3749124e82856d4bfcf3106fbe53b84fd927fe3b36279cb1b2103d75064d4a1cf393ab2f72912f38
data/README.md CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  ✅ Functions over Cartesian vectors are decoupled from dimensionality
14
14
 
15
+ ✅ Define conditions on Cartesian combinations using `s.cond(:set) { |v| v.dim1 > v.dim2 } }` syntax
16
+
15
17
  ✅ Calculate over named dimensions using `s.cartesian { |v| puts "#{v.dim1} and #{v.dim2}" }` syntax
16
18
 
17
19
  ✅ Add functions over dimensions using `s.add_function { |v| v.dim1 + v.dim2 }` syntax
@@ -42,7 +44,7 @@ gem install flex-cartesian-*.gem
42
44
 
43
45
  ## Usage
44
46
 
45
- ```
47
+ ```ruby
46
48
  #!/usr/bin/ruby
47
49
 
48
50
  require 'flex-cartesian'
@@ -51,6 +53,9 @@ require 'flex-cartesian'
51
53
 
52
54
  # BASIC CONCEPTS
53
55
 
56
+ # 1. Cartesian object is a set of combinations of values of dimansions.
57
+ # 2. Dimensions always have names.
58
+
54
59
  puts "\nDefine named dimensions"
55
60
  example = {
56
61
  dim1: [1, 2],
@@ -69,6 +74,12 @@ end
69
74
 
70
75
  # ITERATION OVER CARTESIAN SPACE
71
76
 
77
+ # 3. Iterator is dimensionality-agnostic, that is, has a vector syntax that hides dimensions under the hood.
78
+ # This keeps foundational code intact, and isolates modifications in the iterator body 'do_something'.
79
+ # 4. For efficiency on VERY largse Cartesian spaces, there are
80
+ # a). lazy evaluation of each combination
81
+ # b). progress bar to track time-consuming calculations.
82
+
72
83
  puts "\nIterate over all Cartesian combinations and execute action (dimensionality-agnostic style)"
73
84
  s.cartesian { |v| do_something(v) }
74
85
 
@@ -85,6 +96,12 @@ s.cartesian(lazy: true).take(2).each { |v| do_something(v) }
85
96
 
86
97
  # FUNCTIONS ON CARTESIAN SPACE
87
98
 
99
+ # 5. A function is a virtual dimension that is calculated based on a vector of base dimensions.
100
+ # You can think of a function as a scalar field defined on Cartesian space.
101
+ # 6. Functions are printed as virtual dimensions in .output method.
102
+ # 7. However, functions remains virtual construct, and their values can't be referenced by name
103
+ # (unlike regular dimensions). Also, functions do not add to .size of Cartesian space.
104
+
88
105
  puts "\nAdd function 'triple'"
89
106
  puts "Note: function is visualized in .output as a new dimension"
90
107
  s.add_function(:triple) { |v| v.dim1 * 3 + (v.dim3 ? 1: 0) }
@@ -97,6 +114,28 @@ s.remove_function(:test)
97
114
 
98
115
 
99
116
 
117
+ # CONDITIONS ON CARTESIAN SPACE
118
+
119
+ # 8. A condition is a logical restriction of allowed combitnations for Cartesian space.
120
+ # 9. Using conditions, you can take a slice of Cartesian space.
121
+ # In particular, you can reflect semantical dependency of dimensional values.
122
+
123
+ puts "Build Cartesian space that includes only odd values of 'dim1' dimension"
124
+ s.cond(:set) { |v| v.dim1.odd? }
125
+ puts "print all the conditions in format 'index | condition '"
126
+ s.cond
127
+ puts "Test the condition: print the updated Cartesian space"
128
+ s.output
129
+ puts "Test the condition: check the updated size of Cartesian space"
130
+ puts "New size: #{s.size}"
131
+ puts "Clear condition #0"
132
+ s.cond(:unset, index: 0)
133
+ puts "Clear all conditions"
134
+ s.cond(:clear)
135
+ puts "Restored size without conditions: #{s.size}"
136
+
137
+
138
+
100
139
  # PRINT
101
140
 
102
141
  puts "\nPrint Cartesian space as plain table, all functions included"
@@ -125,7 +164,7 @@ s.export('example.yaml', format: :yaml)
125
164
  # UTILITIES
126
165
 
127
166
  puts "\nGet number of Cartesian combinations"
128
- puts "Note: .size counts only dimenstions, it ignores functions"
167
+ puts "Note: .size counts only dimensions, it ignores virtual constructs (functions, conditions, etc.)"
129
168
  puts "Total size of Cartesian space: #{s.size}"
130
169
 
131
170
  puts "\nPartially converting Cartesian space to array:"
@@ -278,6 +317,23 @@ Example:
278
317
  s.cartesian { |v| v.output(colorize: true, align: false) }
279
318
  ```
280
319
 
320
+ ---
321
+
322
+ ### Conditions on Cartesian Space
323
+ cond(command = :print, # or :set, :unset, :clear
324
+ index: nil, # index of a conditions to unset
325
+ &block # defintiion of the condition to set
326
+ )
327
+ Example:
328
+ ```ruby
329
+ s.cond(:set) { |v| v.dim1 > v.dim3 }
330
+ s.cond # defaults to s.cond(:print) and shows all the conditions in the form 'index | definition'
331
+ s.cond(:unset, 0) # remove previously set condition
332
+ s.cond(:clear) # remove all conditions, if any
333
+ ```
334
+
335
+
336
+
281
337
  ## License
282
338
 
283
339
  This project is licensed under the terms of the GNU General Public License v3.0.
@@ -3,6 +3,7 @@ require 'progressbar'
3
3
  require 'colorize'
4
4
  require 'json'
5
5
  require 'yaml'
6
+ require 'method_source'
6
7
 
7
8
  module FlexOutput
8
9
  def output(separator: " | ", colorize: false, align: true)
@@ -27,9 +28,30 @@ class FlexCartesian
27
28
 
28
29
  def initialize(dimensions = nil)
29
30
  @dimensions = dimensions
31
+ @conditions = []
30
32
  @derived = {}
31
33
  end
32
34
 
35
+ def cond(command = :print, index: nil, &block)
36
+ case command
37
+ when :set
38
+ raise ArgumentError, "Block required" unless block_given?
39
+ @conditions << block
40
+ self
41
+ when :unset
42
+ raise ArgumentError, "Index of the condition required" unless index
43
+ @conditions.delete_at(index)
44
+ when :clear
45
+ @conditions.clear
46
+ self
47
+ when :print
48
+ return if @conditions.empty?
49
+ @conditions.each_with_index { |cond, idx| puts "#{idx} | #{cond.source.gsub(/^.*?\s/, '')}" }
50
+ else
51
+ raise ArgumentError, "unknown condition command: #{command}"
52
+ end
53
+ end
54
+
33
55
  def add_function(name, &block)
34
56
  raise ArgumentError, "Block required" unless block_given?
35
57
  @derived[name.to_sym] = block
@@ -61,18 +83,26 @@ class FlexCartesian
61
83
  struct_instance.define_singleton_method(name) { block.call(struct_instance) }
62
84
  end
63
85
 
86
+ next if @conditions.any? { |cond| !cond.call(struct_instance) }
87
+
64
88
  yield struct_instance
65
89
  end
66
90
  end
67
91
 
68
- def size(dims = nil)
69
- dimensions = dims || @dimensions
70
- return 0 unless dimensions.is_a?(Hash)
71
-
72
- values = dimensions.values.map { |dim| dim.is_a?(Enumerable) ? dim.to_a : [dim] }
73
- return 0 if values.any?(&:empty?)
74
-
75
- values.map(&:size).inject(1, :*)
92
+ def size
93
+ return 0 unless @dimensions.is_a?(Hash)
94
+ if @conditions.empty?
95
+ values = @dimensions.values.map { |dim| dim.is_a?(Enumerable) ? dim.to_a : [dim] }
96
+ return 0 if values.any?(&:empty?)
97
+ values.map(&:size).inject(1, :*)
98
+ else
99
+ size = 0
100
+ cartesian do |v|
101
+ next if @conditions.any? { |cond| !cond.call(v) }
102
+ size += 1
103
+ end
104
+ size
105
+ end
76
106
  end
77
107
 
78
108
  def to_a(limit: nil)
@@ -84,11 +114,10 @@ end
84
114
  result
85
115
  end
86
116
 
87
- def progress_each(dims = nil, lazy: false, title: "Processing")
88
- total = size(dims)
89
- bar = ProgressBar.create(title: title, total: total, format: '%t [%B] %p%% %e')
117
+ def progress_each(lazy: false, title: "Processing")
118
+ bar = ProgressBar.create(title: title, total: size, format: '%t [%B] %p%% %e')
90
119
 
91
- cartesian(dims, lazy: lazy) do |v|
120
+ cartesian(@dimensions, lazy: lazy) do |v|
92
121
  yield v
93
122
  bar.increment
94
123
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flex-cartesian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yury Rassokhin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-08 00:00:00.000000000 Z
11
+ date: 2025-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -52,10 +52,24 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: method_source
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
55
69
  description: 'Flexible and human-friendly Cartesian product enumerator for Ruby. Supports
56
- functions on cartesian, dimensionality-agnostic/dimensionality-aware iterators,
57
- named dimensions, tabular output, lazy/eager evaluation, progress bar, import from
58
- JSON/YAML, and export to Markdown/CSV. Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage'
70
+ functions and conditions on cartesian, dimensionality-agnostic/dimensionality-aware
71
+ iterators, named dimensions, tabular output, lazy/eager evaluation, progress bar,
72
+ import from JSON/YAML, and export to Markdown/CSV. Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage'
59
73
  email:
60
74
  - yuri.rassokhin@gmail.com
61
75
  executables: []