flex-cartesian 0.1.8 → 0.1.9
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/CHANGELOG.md +10 -0
- data/README.md +130 -31
- data/lib/flex-cartesian.rb +38 -6
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b26211b52fac8e2a26ff5408d422e6ae328aefbd67d0a18ac07ef0404006c05
|
4
|
+
data.tar.gz: cf406e24632a26605b5002e91ddfdf63bddaeb0a361d2dbbab76f5514bfdec88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cb31e4b65dba494aeac390ad1baee384c5eca90aeb67363cb374db4ba0c1e4b4d4f4dc6acac088642a751e9d7d4ee996b98c99abf49fdc98c615981c5c12663
|
7
|
+
data.tar.gz: 2b9c27d532a24430cbd21508d91d02d2f29172d9069eab75a8af5c60a2fb25936ff014de5ffc6c5a7df29e08d07de1b7272aefb6edbc907f60a96ae1e1520236
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.1.9 - 2025-07-08
|
4
|
+
### Fixed
|
5
|
+
- Documentation
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Unified methods for import and export
|
9
|
+
- JSON and YAML can be imported, not only exported
|
10
|
+
- Functions can be removed
|
11
|
+
- Minor changes in default values of named parameters
|
12
|
+
|
3
13
|
## 0.1.8 - 2025-07-07
|
4
14
|
### Fixed
|
5
15
|
- Documentation
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
**Ruby implementation of flexible and human-friendly operations on Cartesian products**
|
4
4
|
|
5
|
+
|
6
|
+
|
5
7
|
## Features
|
6
8
|
|
7
9
|
✅ Named dimensions with arbitrary keys
|
@@ -12,16 +14,22 @@
|
|
12
14
|
|
13
15
|
✅ Calculate over named dimensions using `s.cartesian { |v| puts "#{v.dim1} and #{v.dim2}" }` syntax
|
14
16
|
|
17
|
+
✅ Add functions over dimensions using `s.add_function { |v| v.dim1 + v.dim2 }` syntax
|
18
|
+
|
15
19
|
✅ Lazy and eager evaluation
|
16
20
|
|
17
|
-
✅ Progress bars for large Cartesian combinations
|
21
|
+
✅ Progress bars for large Cartesian combinations
|
18
22
|
|
19
|
-
✅ Export of Cartesian space to Markdown or CSV
|
23
|
+
✅ Export of Cartesian space to Markdown or CSV
|
20
24
|
|
21
|
-
✅ Import of
|
25
|
+
✅ Import of Cartesian space from JSON or YAML
|
26
|
+
|
27
|
+
✅ Export of Cartesian space to Markdown or CSV
|
22
28
|
|
23
29
|
✅ Structured and colorized terminal output
|
24
30
|
|
31
|
+
|
32
|
+
|
25
33
|
## Installation
|
26
34
|
|
27
35
|
```bash
|
@@ -30,53 +38,103 @@ gem build flex-cartesian.gemspec
|
|
30
38
|
gem install flex-cartesian-*.gem
|
31
39
|
```
|
32
40
|
|
41
|
+
|
42
|
+
|
33
43
|
## Usage
|
34
44
|
|
35
|
-
```
|
45
|
+
```
|
46
|
+
#!/usr/bin/ruby
|
47
|
+
|
36
48
|
require 'flex-cartesian'
|
37
49
|
|
38
|
-
|
50
|
+
|
51
|
+
|
52
|
+
# BASIC CONCEPTS
|
53
|
+
|
54
|
+
puts "\nDefine named dimensions"
|
39
55
|
example = {
|
40
56
|
dim1: [1, 2],
|
41
57
|
dim2: ['x', 'y'],
|
42
58
|
dim3: [true, false]
|
43
59
|
}
|
60
|
+
|
61
|
+
puts "\nCreate Cartesian space"
|
44
62
|
s = FlexCartesian.new(example)
|
45
63
|
|
46
|
-
|
47
|
-
|
64
|
+
def do_something(v)
|
65
|
+
# do something here on vector v and its components
|
66
|
+
end
|
48
67
|
|
49
|
-
# Get number of Cartesian combinations:
|
50
|
-
puts "Total size: #{s.size}"
|
51
68
|
|
52
|
-
# Convert Cartesian space to array of combinations
|
53
|
-
array = s.to_a(limit: 3)
|
54
|
-
puts array.inspect
|
55
69
|
|
56
|
-
|
57
|
-
end
|
70
|
+
# ITERATION OVER CARTESIAN SPACE
|
58
71
|
|
59
|
-
|
72
|
+
puts "\nIterate over all Cartesian combinations and execute action (dimensionality-agnostic style)"
|
73
|
+
s.cartesian { |v| do_something(v) }
|
74
|
+
|
75
|
+
puts "\nIterate over all Cartesian combinations and execute action (dimensionality-aware style)"
|
76
|
+
s.cartesian { |v| puts "#{v.dim1} & #{v.dim2}" if v.dim3 }
|
77
|
+
|
78
|
+
puts "\nIterate and display progress bar (useful for large Cartesian spaces)"
|
60
79
|
s.progress_each { |v| do_something(v) }
|
61
80
|
|
62
|
-
|
63
|
-
s.
|
81
|
+
puts "\nIterate in lLazy mode, without materializing entire Cartesian product in memory"
|
82
|
+
s.cartesian(lazy: true).take(2).each { |v| do_something(v) }
|
64
83
|
|
65
|
-
# Lazy evaluation without materializing entire Cartesian product in memory:
|
66
|
-
s.cartesian(lazy: true).take(2).each { |v| puts v.inspect }
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
|
85
|
+
|
86
|
+
# FUNCTIONS ON CARTESIAN SPACE
|
87
|
+
|
88
|
+
puts "\nAdd function 'triple'"
|
89
|
+
puts "Note: function is visualized in .output as a new dimension"
|
90
|
+
s.add_function(:triple) { |v| v.dim1 * 3 + (v.dim3 ? 1: 0) }
|
91
|
+
# Note: however, function remains a virtual construct, and it cannot be referenced by name
|
92
|
+
s.output
|
93
|
+
|
94
|
+
puts "\Add and then remove function 'test'"
|
95
|
+
s.add_function(:test) { |v| v.dim3.to_i }
|
96
|
+
s.remove_function(:test)
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
# PRINT
|
101
|
+
|
102
|
+
puts "\nPrint Cartesian space as plain table, all functions included"
|
71
103
|
s.output
|
72
104
|
|
73
|
-
|
74
|
-
s.output(format: :markdown
|
105
|
+
puts "\nPrint Cartesian space as Markdown"
|
106
|
+
s.output(format: :markdown)
|
75
107
|
|
76
|
-
|
108
|
+
puts "\nPrint Cartesian space as CSV"
|
77
109
|
s.output(format: :csv)
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
# IMPORT / EXPORT
|
114
|
+
|
115
|
+
puts "\nImport Cartesian space from JSON (similar method for YAML)"
|
116
|
+
File.write('example.json', JSON.pretty_generate(example))
|
117
|
+
puts "\nNote: after import, all assigned functions will calculate again, and they appear in the output"
|
118
|
+
s.import('example.json').output
|
119
|
+
|
120
|
+
puts "\nExport Cartesian space to YAML (similar method for JSON)"
|
121
|
+
s.export('example.yaml', format: :yaml)
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
# UTILITIES
|
126
|
+
|
127
|
+
puts "\nGet number of Cartesian combinations"
|
128
|
+
puts "Note: .size counts only dimenstions, it ignores functions"
|
129
|
+
puts "Total size of Cartesian space: #{s.size}"
|
130
|
+
|
131
|
+
puts "\nPartially converting Cartesian space to array:"
|
132
|
+
array = s.to_a(limit: 3)
|
133
|
+
puts array.inspect
|
78
134
|
```
|
79
135
|
|
136
|
+
|
137
|
+
|
80
138
|
## API Overview
|
81
139
|
|
82
140
|
### Initialization
|
@@ -116,6 +174,33 @@ s.cartesian { |v| puts "#{v.dim1} - #{v.dim2}" }
|
|
116
174
|
|
117
175
|
---
|
118
176
|
|
177
|
+
### Add / Remove Functions
|
178
|
+
```ruby
|
179
|
+
add_function(name, &block)
|
180
|
+
remove_function(name)
|
181
|
+
```
|
182
|
+
- `name`: symbol — the name of the virtual dimension (e.g. `:label`)
|
183
|
+
- `block`: a function that receives each vector and returns a computed value
|
184
|
+
|
185
|
+
Functions show up in `.output` like additional (virtual) dimensions.
|
186
|
+
|
187
|
+
Example:
|
188
|
+
```ruby
|
189
|
+
s = FlexCartesian.new( { dim1: [1, 2], dim2: ['A', 'B'] } )
|
190
|
+
s.add_function(:increment) { |v| v.dim1 + 1 }
|
191
|
+
|
192
|
+
s.output(format: :markdown)
|
193
|
+
# | dim1 | dim2 | increment |
|
194
|
+
# |------|------|--------|
|
195
|
+
# | 1 | "A" | 2 |
|
196
|
+
# | 1 | "B" | 2 |
|
197
|
+
# ...
|
198
|
+
```
|
199
|
+
|
200
|
+
> Note: functions are virtual — they are not part of the base dimensions, but they integrate seamlessly in output.
|
201
|
+
|
202
|
+
---
|
203
|
+
|
119
204
|
### Count Total Combinations
|
120
205
|
```ruby
|
121
206
|
size(dims = nil) → Integer
|
@@ -161,22 +246,36 @@ Markdown example:
|
|
161
246
|
|
162
247
|
---
|
163
248
|
|
164
|
-
###
|
249
|
+
### Import from JSON or YAML
|
250
|
+
```ruby
|
251
|
+
import('file.json',
|
252
|
+
format: :json) # or :yaml
|
253
|
+
```
|
254
|
+
|
255
|
+
Obsolete import methods:
|
256
|
+
```ruby
|
257
|
+
s.from_json("file.json")
|
258
|
+
s.from_yaml("file.yaml")
|
259
|
+
```
|
260
|
+
|
261
|
+
---
|
262
|
+
|
263
|
+
### Export from JSON or YAML
|
165
264
|
```ruby
|
166
|
-
|
167
|
-
|
265
|
+
export('file.json',
|
266
|
+
format: :json) # or :yaml
|
168
267
|
```
|
169
268
|
|
170
269
|
---
|
171
270
|
|
172
|
-
###
|
271
|
+
### Print Cartesian Space
|
173
272
|
Each yielded combination is a `Struct` extended with:
|
174
273
|
```ruby
|
175
|
-
output(separator: " | ", colorize: false, align:
|
274
|
+
output(separator: " | ", colorize: false, align: true)
|
176
275
|
```
|
177
276
|
Example:
|
178
277
|
```ruby
|
179
|
-
s.cartesian { |v| v.output(colorize: true, align:
|
278
|
+
s.cartesian { |v| v.output(colorize: true, align: false) }
|
180
279
|
```
|
181
280
|
|
182
281
|
## License
|
data/lib/flex-cartesian.rb
CHANGED
@@ -5,7 +5,7 @@ require 'json'
|
|
5
5
|
require 'yaml'
|
6
6
|
|
7
7
|
module FlexOutput
|
8
|
-
def output(separator: " | ", colorize: false, align:
|
8
|
+
def output(separator: " | ", colorize: false, align: true)
|
9
9
|
return puts "(empty struct)" unless respond_to?(:members) && respond_to?(:values)
|
10
10
|
|
11
11
|
values_list = members.zip(values.map { |v| v.inspect })
|
@@ -35,6 +35,10 @@ class FlexCartesian
|
|
35
35
|
@derived[name.to_sym] = block
|
36
36
|
end
|
37
37
|
|
38
|
+
def remove_function(name)
|
39
|
+
@derived.delete(name.to_sym)
|
40
|
+
end
|
41
|
+
|
38
42
|
def cartesian(dims = nil, lazy: false)
|
39
43
|
dimensions = dims || @dimensions
|
40
44
|
return nil unless dimensions.is_a?(Hash)
|
@@ -90,7 +94,7 @@ end
|
|
90
94
|
end
|
91
95
|
end
|
92
96
|
|
93
|
-
def output(separator: " | ", colorize: false, align:
|
97
|
+
def output(separator: " | ", colorize: false, align: true, format: :plain, limit: nil)
|
94
98
|
rows = []
|
95
99
|
cartesian do |v|
|
96
100
|
rows << v
|
@@ -123,14 +127,42 @@ end
|
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
126
|
-
|
130
|
+
def import(path, format: :json)
|
131
|
+
data = case format
|
132
|
+
when :json
|
133
|
+
JSON.parse(File.read(path), symbolize_names: true)
|
134
|
+
when :yaml
|
135
|
+
YAML.safe_load(File.read(path), symbolize_names: true)
|
136
|
+
else
|
137
|
+
raise ArgumentError, "Unsupported format: #{format}. Only :json and :yaml are supported."
|
138
|
+
end
|
139
|
+
|
140
|
+
raise TypeError, "Expected parsed data to be a Hash" unless data.is_a?(Hash)
|
141
|
+
|
142
|
+
@dimensions = data
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def export(path, format: :json)
|
147
|
+
case format
|
148
|
+
when :json
|
149
|
+
File.write(path, JSON.pretty_generate(@dimensions))
|
150
|
+
when :yaml
|
151
|
+
File.write(path, YAML.dump(@dimensions))
|
152
|
+
else
|
153
|
+
raise ArgumentError, "Unsupported format: #{format}. Only :json and :yaml are supported."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def from_json(path)
|
127
159
|
data = JSON.parse(File.read(path), symbolize_names: true)
|
128
|
-
|
160
|
+
@dimensions = data
|
129
161
|
end
|
130
162
|
|
131
|
-
def
|
163
|
+
def from_yaml(path)
|
132
164
|
data = YAML.safe_load(File.read(path), symbolize_names: true)
|
133
|
-
|
165
|
+
@dimensions = data
|
134
166
|
end
|
135
167
|
|
136
168
|
private
|
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.
|
4
|
+
version: 0.1.9
|
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-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -53,9 +53,9 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.0'
|
55
55
|
description: 'Flexible and human-friendly Cartesian product enumerator for Ruby. Supports
|
56
|
-
|
57
|
-
lazy/eager evaluation, progress bar,
|
58
|
-
Code example: https://github.com/Yuri-Rassokhin/flex-cartesian/blob/main/README.md#usage'
|
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'
|
59
59
|
email:
|
60
60
|
- yuri.rassokhin@gmail.com
|
61
61
|
executables: []
|