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.
- checksums.yaml +4 -4
- data/README.md +58 -2
- data/lib/flex-cartesian.rb +41 -12
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b34c40aea1692a248f2f4ee506b8b7a5a66a8257f90b1f74a7613897f8047c4
|
4
|
+
data.tar.gz: 3fb4c691a65ebcda1f9606368f436ba1ebee56749dee9e27d04296884cfef26e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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.
|
data/lib/flex-cartesian.rb
CHANGED
@@ -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
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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(
|
88
|
-
|
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(
|
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.
|
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-
|
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
|
57
|
-
named dimensions, tabular output, lazy/eager evaluation, progress bar,
|
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: []
|