keybreak 0.2.0 → 0.3.0
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/.rspec +2 -1
- data/CHANGELOG.md +6 -0
- data/README.md +355 -349
- data/examples/{empty_key.rb → empty_keys.rb} +11 -8
- data/examples/nested_keys.rb +65 -0
- data/examples/nested_keys2.rb +64 -0
- data/examples/nested_sum.rb +55 -52
- data/examples/nested_sum2.rb +58 -0
- data/keybreak.gemspec +1 -0
- data/lib/keybreak/controller.rb +2 -0
- data/lib/keybreak/version.rb +1 -1
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1cc4542e1cff84c14f701250bfe7797a618371e
|
|
4
|
+
data.tar.gz: a1f3cd7c78f43bc1d6b24b1dcd267b97faa3f5bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4221eb518702614f0c7b98c5feb5c171f1792b0893a96ede9cf9dcd953e1b4b3ed16f9060f29c75fcd53580fcdae39776b2a1846971e2bd12d112229402b051b
|
|
7
|
+
data.tar.gz: 3653bc51a73bbbff5e9a394eb394f74bfe5c8534fa9cef7cba742701249ecd9c90285e688f36b61a6599056209c97652bf6973ee9f291684259e5809a44f75a5
|
data/.rspec
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
--format documentation
|
|
1
|
+
--format documentation
|
|
2
|
+
--color
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -1,349 +1,355 @@
|
|
|
1
|
-
# Keybreak
|
|
2
|
-
|
|
3
|
-
Keybreak is a utility module for key break processing in Ruby.
|
|
4
|
-
|
|
5
|
-
## Introduction
|
|
6
|
-
|
|
7
|
-
### Key break processing
|
|
8
|
-
|
|
9
|
-
The "key break processing" means, assuming a sorted sequence of records which can be grouped by a column,
|
|
10
|
-
doing the same process for each group.
|
|
11
|
-
|
|
12
|
-
The column used for the grouping is a "key".
|
|
13
|
-
In processing the record sequence, when the key's value in a record changes from the previous record,
|
|
14
|
-
it is called "key break".
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
### Motivation
|
|
18
|
-
|
|
19
|
-
A typical key break processing is counting the number of records for each key like below:
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
RECORDS =<<EOD
|
|
23
|
-
a 1
|
|
24
|
-
b 2
|
|
25
|
-
b 3
|
|
26
|
-
c 4
|
|
27
|
-
c 5
|
|
28
|
-
c 6
|
|
29
|
-
d 7
|
|
30
|
-
e 8
|
|
31
|
-
e 9
|
|
32
|
-
EOD
|
|
33
|
-
|
|
34
|
-
count = 0
|
|
35
|
-
prev_key = nil
|
|
36
|
-
|
|
37
|
-
RECORDS.each_line do |line|
|
|
38
|
-
key = line.split("\t")[0]
|
|
39
|
-
|
|
40
|
-
if !prev_key.nil? && key != prev_key
|
|
41
|
-
puts "#{prev_key}:#{count}"
|
|
42
|
-
count = 0
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
count += 1
|
|
46
|
-
prev_key = key
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
if !prev_key.nil?
|
|
50
|
-
puts "#{prev_key}:#{count}"
|
|
51
|
-
end
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Note that you have to write "puts" once again after the iteration.
|
|
55
|
-
This is quite troublesome even for such a simple task, and is very my motivation.
|
|
56
|
-
|
|
57
|
-
With Keybreak module, the code goes like below:
|
|
58
|
-
|
|
59
|
-
```ruby
|
|
60
|
-
require "keybreak"
|
|
61
|
-
|
|
62
|
-
RECORDS =<<EOD
|
|
63
|
-
a 1
|
|
64
|
-
b 2
|
|
65
|
-
b 3
|
|
66
|
-
c 4
|
|
67
|
-
c 5
|
|
68
|
-
c 6
|
|
69
|
-
d 7
|
|
70
|
-
e 8
|
|
71
|
-
e 9
|
|
72
|
-
EOD
|
|
73
|
-
|
|
74
|
-
Keybreak.execute_with_controller do |c, count|
|
|
75
|
-
c.on(:keystart) {count = 0}
|
|
76
|
-
c.on(:keyend) {|key| puts "#{key}:#{count}"}
|
|
77
|
-
|
|
78
|
-
RECORDS.each_line do |line|
|
|
79
|
-
key = line.split("\t")[0]
|
|
80
|
-
c.feed(key)
|
|
81
|
-
count += 1
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
You need to register event handlers as a key break consists of two events:
|
|
87
|
-
First, the end of current key sequence (:keyend).
|
|
88
|
-
Next, the start of new key sequence (:keystart).
|
|
89
|
-
|
|
90
|
-
Then call feed() in your record loop.
|
|
91
|
-
The method holds current key, detects a key break, and calls the event handlers accordingly.
|
|
92
|
-
The block given to execute_with_controller makes sure to process the end of the last key.
|
|
93
|
-
|
|
94
|
-
In many cases, taking a functional approach such as Enumerable#map, Enumerable#slice_when, etc. would achieve the task simply.
|
|
95
|
-
But sometimes, a procedural code is needed.
|
|
96
|
-
Keybreak module may assist you to make your key break code simpler.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
## Installation
|
|
100
|
-
|
|
101
|
-
Add this line to your application's Gemfile:
|
|
102
|
-
|
|
103
|
-
```ruby
|
|
104
|
-
gem 'keybreak'
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
And then execute:
|
|
108
|
-
|
|
109
|
-
$ bundle
|
|
110
|
-
|
|
111
|
-
Or install it yourself as:
|
|
112
|
-
|
|
113
|
-
$ gem install keybreak
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
## Usage
|
|
117
|
-
|
|
118
|
-
In your ruby source, write the line below:
|
|
119
|
-
|
|
120
|
-
```ruby
|
|
121
|
-
require "keybreak"
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Here are some examples of typical key break processing.
|
|
125
|
-
See [examples](https://github.com/hashimoton/keybreak/tree/master/examples) for full code.
|
|
126
|
-
|
|
127
|
-
### Print first values for each key
|
|
128
|
-
|
|
129
|
-
Register a :keystart handler which prints the given key and value.
|
|
130
|
-
|
|
131
|
-
```ruby
|
|
132
|
-
RECORDS =<<EOD
|
|
133
|
-
a 1
|
|
134
|
-
b 2
|
|
135
|
-
b 3
|
|
136
|
-
c 4
|
|
137
|
-
c 5
|
|
138
|
-
c 6
|
|
139
|
-
d 7
|
|
140
|
-
e 8
|
|
141
|
-
e 9
|
|
142
|
-
EOD
|
|
143
|
-
|
|
144
|
-
Keybreak.execute_with_controller do |c|
|
|
145
|
-
c.on(:keystart) {|key, value| puts "#{key}:#{value}"}
|
|
146
|
-
|
|
147
|
-
RECORDS.each_line do |line|
|
|
148
|
-
key, value = line.split("\t")
|
|
149
|
-
c.feed(key, value)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
The result will be:
|
|
155
|
-
|
|
156
|
-
```
|
|
157
|
-
a:1
|
|
158
|
-
b:2
|
|
159
|
-
c:4
|
|
160
|
-
d:7
|
|
161
|
-
e:8
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Print last values for each key
|
|
165
|
-
|
|
166
|
-
Borrows RECORDS from above example.
|
|
167
|
-
|
|
168
|
-
Register a :keyend handler which prints the given key and value.
|
|
169
|
-
|
|
170
|
-
```ruby
|
|
171
|
-
Keybreak.execute_with_controller do |c|
|
|
172
|
-
c.on(:keyend) {|key, value| puts "#{key}:#{value}"}
|
|
173
|
-
|
|
174
|
-
RECORDS.each_line do |line|
|
|
175
|
-
key, value = line.split("\t")
|
|
176
|
-
c.feed(key, value)
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
The result will be:
|
|
182
|
-
|
|
183
|
-
```
|
|
184
|
-
a:1
|
|
185
|
-
b:3
|
|
186
|
-
c:6
|
|
187
|
-
d:7
|
|
188
|
-
e:9
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Print sum of values for each key
|
|
192
|
-
|
|
193
|
-
Clear sum when a key starts.
|
|
194
|
-
Print sum when the key ends.
|
|
195
|
-
|
|
196
|
-
```ruby
|
|
197
|
-
Keybreak.execute_with_controller do |c, sum|
|
|
198
|
-
c.on(:keystart) {sum = 0}
|
|
199
|
-
c.on(:keyend) {|key| puts "#{key}:#{sum}"}
|
|
200
|
-
|
|
201
|
-
RECORDS.each_line do |line|
|
|
202
|
-
key, value = line.split("\t")
|
|
203
|
-
c.feed(key)
|
|
204
|
-
sum += value.to_i
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
The result will be:
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
a:1
|
|
213
|
-
b:5
|
|
214
|
-
c:15
|
|
215
|
-
d:7
|
|
216
|
-
e:17
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
### Print sum of values for each key and sub key
|
|
221
|
-
|
|
222
|
-
Nest Keybreak.execute_with_controller.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
so that
|
|
226
|
-
|
|
227
|
-
```ruby
|
|
228
|
-
RECORDS =<<EOD
|
|
229
|
-
a a1 1
|
|
230
|
-
b b1 2
|
|
231
|
-
b b2 3
|
|
232
|
-
c c1 4
|
|
233
|
-
c c1 5
|
|
234
|
-
c c2 6
|
|
235
|
-
d d1 7
|
|
236
|
-
e e1 8
|
|
237
|
-
e e1 9
|
|
238
|
-
EOD
|
|
239
|
-
|
|
240
|
-
Keybreak.execute_with_controller do |c, sum|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
total
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
total
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
puts "#{
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
1
|
+
# Keybreak
|
|
2
|
+
|
|
3
|
+
Keybreak is a utility module for key break processing in Ruby.
|
|
4
|
+
|
|
5
|
+
## Introduction
|
|
6
|
+
|
|
7
|
+
### Key break processing
|
|
8
|
+
|
|
9
|
+
The "key break processing" means, assuming a sorted sequence of records which can be grouped by a column,
|
|
10
|
+
doing the same process for each group.
|
|
11
|
+
|
|
12
|
+
The column used for the grouping is a "key".
|
|
13
|
+
In processing the record sequence, when the key's value in a record changes from the previous record,
|
|
14
|
+
it is called "key break" (also known as ["control break"](https://en.wikipedia.org/wiki/Control_break)).
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Motivation
|
|
18
|
+
|
|
19
|
+
A typical key break processing is counting the number of records for each key like below:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
RECORDS =<<EOD
|
|
23
|
+
a 1
|
|
24
|
+
b 2
|
|
25
|
+
b 3
|
|
26
|
+
c 4
|
|
27
|
+
c 5
|
|
28
|
+
c 6
|
|
29
|
+
d 7
|
|
30
|
+
e 8
|
|
31
|
+
e 9
|
|
32
|
+
EOD
|
|
33
|
+
|
|
34
|
+
count = 0
|
|
35
|
+
prev_key = nil
|
|
36
|
+
|
|
37
|
+
RECORDS.each_line do |line|
|
|
38
|
+
key = line.split("\t")[0]
|
|
39
|
+
|
|
40
|
+
if !prev_key.nil? && key != prev_key
|
|
41
|
+
puts "#{prev_key}:#{count}"
|
|
42
|
+
count = 0
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
count += 1
|
|
46
|
+
prev_key = key
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if !prev_key.nil?
|
|
50
|
+
puts "#{prev_key}:#{count}"
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Note that you have to write "puts" once again after the iteration.
|
|
55
|
+
This is quite troublesome even for such a simple task, and is very my motivation.
|
|
56
|
+
|
|
57
|
+
With Keybreak module, the code goes like below:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
require "keybreak"
|
|
61
|
+
|
|
62
|
+
RECORDS =<<EOD
|
|
63
|
+
a 1
|
|
64
|
+
b 2
|
|
65
|
+
b 3
|
|
66
|
+
c 4
|
|
67
|
+
c 5
|
|
68
|
+
c 6
|
|
69
|
+
d 7
|
|
70
|
+
e 8
|
|
71
|
+
e 9
|
|
72
|
+
EOD
|
|
73
|
+
|
|
74
|
+
Keybreak.execute_with_controller do |c, count|
|
|
75
|
+
c.on(:keystart) {count = 0}
|
|
76
|
+
c.on(:keyend) {|key| puts "#{key}:#{count}"}
|
|
77
|
+
|
|
78
|
+
RECORDS.each_line do |line|
|
|
79
|
+
key = line.split("\t")[0]
|
|
80
|
+
c.feed(key)
|
|
81
|
+
count += 1
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
You need to register event handlers as a key break consists of two events:
|
|
87
|
+
First, the end of current key sequence (:keyend).
|
|
88
|
+
Next, the start of new key sequence (:keystart).
|
|
89
|
+
|
|
90
|
+
Then call feed() in your record loop.
|
|
91
|
+
The method holds current key, detects a key break, and calls the event handlers accordingly.
|
|
92
|
+
The block given to execute_with_controller makes sure to process the end of the last key.
|
|
93
|
+
|
|
94
|
+
In many cases, taking a functional approach such as Enumerable#map, Enumerable#slice_when, etc. would achieve the task simply.
|
|
95
|
+
But sometimes, a procedural code is needed.
|
|
96
|
+
Keybreak module may assist you to make your key break processing code simpler.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Installation
|
|
100
|
+
|
|
101
|
+
Add this line to your application's Gemfile:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
gem 'keybreak'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
And then execute:
|
|
108
|
+
|
|
109
|
+
$ bundle
|
|
110
|
+
|
|
111
|
+
Or install it yourself as:
|
|
112
|
+
|
|
113
|
+
$ gem install keybreak
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
## Usage
|
|
117
|
+
|
|
118
|
+
In your ruby source, write the line below:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
require "keybreak"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Here are some examples of typical key break processing.
|
|
125
|
+
See [examples](https://github.com/hashimoton/keybreak/tree/master/examples) for full code.
|
|
126
|
+
|
|
127
|
+
### Print first values for each key
|
|
128
|
+
|
|
129
|
+
Register a :keystart handler which prints the given key and value.
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
RECORDS =<<EOD
|
|
133
|
+
a 1
|
|
134
|
+
b 2
|
|
135
|
+
b 3
|
|
136
|
+
c 4
|
|
137
|
+
c 5
|
|
138
|
+
c 6
|
|
139
|
+
d 7
|
|
140
|
+
e 8
|
|
141
|
+
e 9
|
|
142
|
+
EOD
|
|
143
|
+
|
|
144
|
+
Keybreak.execute_with_controller do |c|
|
|
145
|
+
c.on(:keystart) {|key, value| puts "#{key}:#{value}"}
|
|
146
|
+
|
|
147
|
+
RECORDS.each_line do |line|
|
|
148
|
+
key, value = line.split("\t")
|
|
149
|
+
c.feed(key, value)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The result will be:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
a:1
|
|
158
|
+
b:2
|
|
159
|
+
c:4
|
|
160
|
+
d:7
|
|
161
|
+
e:8
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Print last values for each key
|
|
165
|
+
|
|
166
|
+
Borrows RECORDS from above example.
|
|
167
|
+
|
|
168
|
+
Register a :keyend handler which prints the given key and value.
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
Keybreak.execute_with_controller do |c|
|
|
172
|
+
c.on(:keyend) {|key, value| puts "#{key}:#{value}"}
|
|
173
|
+
|
|
174
|
+
RECORDS.each_line do |line|
|
|
175
|
+
key, value = line.split("\t")
|
|
176
|
+
c.feed(key, value)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The result will be:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
a:1
|
|
185
|
+
b:3
|
|
186
|
+
c:6
|
|
187
|
+
d:7
|
|
188
|
+
e:9
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Print sum of values for each key
|
|
192
|
+
|
|
193
|
+
Clear sum when a key starts.
|
|
194
|
+
Print sum when the key ends.
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
198
|
+
c.on(:keystart) {sum = 0}
|
|
199
|
+
c.on(:keyend) {|key| puts "#{key}:#{sum}"}
|
|
200
|
+
|
|
201
|
+
RECORDS.each_line do |line|
|
|
202
|
+
key, value = line.split("\t")
|
|
203
|
+
c.feed(key)
|
|
204
|
+
sum += value.to_i
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The result will be:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
a:1
|
|
213
|
+
b:5
|
|
214
|
+
c:15
|
|
215
|
+
d:7
|
|
216
|
+
e:17
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
### Print sum of values for each key and sub key
|
|
221
|
+
|
|
222
|
+
Nest Keybreak.execute_with_controller.
|
|
223
|
+
|
|
224
|
+
Call flush() for sub key in the :keyend handler of the key
|
|
225
|
+
so that an end of key triggers an end of sub key.
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
RECORDS =<<EOD
|
|
229
|
+
a a1 1
|
|
230
|
+
b b1 2
|
|
231
|
+
b b2 3
|
|
232
|
+
c c1 4
|
|
233
|
+
c c1 5
|
|
234
|
+
c c2 6
|
|
235
|
+
d d1 7
|
|
236
|
+
e e1 8
|
|
237
|
+
e e1 9
|
|
238
|
+
EOD
|
|
239
|
+
|
|
240
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
241
|
+
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
242
|
+
c.on(:keystart) {sum = 0}
|
|
243
|
+
c.on(:keyend) do |key|
|
|
244
|
+
sub_c.flush
|
|
245
|
+
puts "total #{key}:#{sum}"
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
249
|
+
sub_c.on(:keyend) do |key|
|
|
250
|
+
puts "#{key}:#{sub_sum}"
|
|
251
|
+
sum += sub_sum
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
RECORDS.each_line do |line|
|
|
255
|
+
key, sub_key, value = line.split("\t")
|
|
256
|
+
c.feed(key)
|
|
257
|
+
sub_c.feed(sub_key)
|
|
258
|
+
sub_sum += value.to_i
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The result will be:
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
a1:1
|
|
268
|
+
total a:1
|
|
269
|
+
b1:2
|
|
270
|
+
b2:3
|
|
271
|
+
total b:5
|
|
272
|
+
c1:9
|
|
273
|
+
c2:6
|
|
274
|
+
total c:15
|
|
275
|
+
d1:7
|
|
276
|
+
total d:7
|
|
277
|
+
e1:17
|
|
278
|
+
total e:17
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Print sum of values for each key where empty key means continuation
|
|
282
|
+
|
|
283
|
+
Sometimes we face the empty keys which mean to continue the value in the previous record.
|
|
284
|
+
The pivot table of MS Excel is an example.
|
|
285
|
+
Keybreak module can handle this case by providing a block for detecting a keybreak.
|
|
286
|
+
|
|
287
|
+
```ruby
|
|
288
|
+
RECORDS =<<EOD
|
|
289
|
+
a a1 1
|
|
290
|
+
b b1 2
|
|
291
|
+
b2 3
|
|
292
|
+
c c1 4
|
|
293
|
+
5
|
|
294
|
+
c2 6
|
|
295
|
+
d d1 7
|
|
296
|
+
e e1 8
|
|
297
|
+
9
|
|
298
|
+
EOD
|
|
299
|
+
|
|
300
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
301
|
+
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
302
|
+
c.on(:detection) {|key| !key.empty?}
|
|
303
|
+
c.on(:keystart) {sum = 0}
|
|
304
|
+
c.on(:keyend) do |key|
|
|
305
|
+
sub_c.flush
|
|
306
|
+
puts "total #{key}:#{sum}"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
sub_c.on(:detection) {|key| !key.empty?}
|
|
310
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
311
|
+
sub_c.on(:keyend) do |key|
|
|
312
|
+
puts "#{key}:#{sub_sum}"
|
|
313
|
+
sum += sub_sum
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
RECORDS.each_line do |line|
|
|
317
|
+
key, sub_key, value = line.split("\t")
|
|
318
|
+
c.feed(key)
|
|
319
|
+
sub_c.feed(sub_key)
|
|
320
|
+
sub_sum += value.to_i
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The result will be the same as the previous example.
|
|
327
|
+
|
|
328
|
+
By default, the below block is used for the key break detections.
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
{|key, prev_key| key != prev_key}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Development
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
### Test
|
|
338
|
+
|
|
339
|
+
Run the tests in spec directory:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
$ cd keybreak
|
|
343
|
+
$ rake spec
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
## Contributing
|
|
348
|
+
|
|
349
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hashimoton/keybreak.
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
## License
|
|
353
|
+
|
|
354
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
355
|
+
|
|
@@ -30,22 +30,25 @@ e e1 8
|
|
|
30
30
|
EOD
|
|
31
31
|
|
|
32
32
|
Keybreak.execute_with_controller do |c, sum|
|
|
33
|
-
c.on(:detection) {|key| !key.empty?}
|
|
34
|
-
c.on(:keystart) {sum = 0}
|
|
35
|
-
c.on(:keyend) {|key| puts "total #{key}:#{sum}"}
|
|
36
|
-
|
|
37
33
|
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
38
|
-
|
|
34
|
+
c.on(:detection) {|key| !key.empty?}
|
|
35
|
+
c.on(:keystart) {sum = 0}
|
|
36
|
+
c.on(:keyend) do |key|
|
|
37
|
+
sub_c.flush
|
|
38
|
+
puts "total #{key}:#{sum}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
sub_c.on(:detection) {|key| !key.empty?}
|
|
39
42
|
sub_c.on(:keystart) {sub_sum = 0}
|
|
40
|
-
sub_c.on(:keyend) do |
|
|
41
|
-
puts "#{
|
|
43
|
+
sub_c.on(:keyend) do |key|
|
|
44
|
+
puts "#{key}:#{sub_sum}"
|
|
42
45
|
sum += sub_sum
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
RECORDS.each_line do |line|
|
|
46
49
|
key, sub_key, value = line.split("\t")
|
|
47
|
-
sub_c.feed([key, sub_key])
|
|
48
50
|
c.feed(key)
|
|
51
|
+
sub_c.feed(sub_key)
|
|
49
52
|
sub_sum += value.to_i
|
|
50
53
|
end
|
|
51
54
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print start and end of each key and sub key
|
|
3
|
+
# =>
|
|
4
|
+
# a START
|
|
5
|
+
# a1 START
|
|
6
|
+
# a1 END
|
|
7
|
+
# a END
|
|
8
|
+
# b START
|
|
9
|
+
# b1 START
|
|
10
|
+
# b1 END
|
|
11
|
+
# b2 START
|
|
12
|
+
# b2 END
|
|
13
|
+
# b END
|
|
14
|
+
# c START
|
|
15
|
+
# c1 START
|
|
16
|
+
# c1 END
|
|
17
|
+
# c2 START
|
|
18
|
+
# c2 END
|
|
19
|
+
# c END
|
|
20
|
+
# d START
|
|
21
|
+
# d1 START
|
|
22
|
+
# d1 END
|
|
23
|
+
# d END
|
|
24
|
+
# e START
|
|
25
|
+
# e1 START
|
|
26
|
+
# e1 END
|
|
27
|
+
# e END
|
|
28
|
+
|
|
29
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
30
|
+
require "keybreak"
|
|
31
|
+
|
|
32
|
+
RECORDS =<<EOD
|
|
33
|
+
a a1 1
|
|
34
|
+
b b1 2
|
|
35
|
+
b b2 3
|
|
36
|
+
c c1 4
|
|
37
|
+
c c1 5
|
|
38
|
+
c c2 6
|
|
39
|
+
d d1 7
|
|
40
|
+
e e1 8
|
|
41
|
+
e e1 9
|
|
42
|
+
EOD
|
|
43
|
+
|
|
44
|
+
Keybreak.execute_with_controller do |c|
|
|
45
|
+
Keybreak.execute_with_controller do |sub_c|
|
|
46
|
+
c.on(:keystart) {|key| puts "#{key} START"}
|
|
47
|
+
c.on(:keyend) do |key|
|
|
48
|
+
sub_c.flush
|
|
49
|
+
puts "#{key} END"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
sub_c.on(:keystart) {|key| puts " #{key} START"}
|
|
53
|
+
sub_c.on(:keyend) do |key|
|
|
54
|
+
puts " #{key} END"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
RECORDS.each_line do |line|
|
|
58
|
+
key, sub_key, value = line.split("\t")
|
|
59
|
+
c.feed(key)
|
|
60
|
+
sub_c.feed(sub_key)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# EOF
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print start and end of each key and sub key
|
|
3
|
+
# =>
|
|
4
|
+
# a START
|
|
5
|
+
# a1 START
|
|
6
|
+
# a1 END
|
|
7
|
+
# a END
|
|
8
|
+
# b START
|
|
9
|
+
# b1 START
|
|
10
|
+
# b1 END
|
|
11
|
+
# b2 START
|
|
12
|
+
# b2 END
|
|
13
|
+
# b END
|
|
14
|
+
# c START
|
|
15
|
+
# c1 START
|
|
16
|
+
# c1 END
|
|
17
|
+
# c2 START
|
|
18
|
+
# c2 END
|
|
19
|
+
# c END
|
|
20
|
+
# d START
|
|
21
|
+
# d1 START
|
|
22
|
+
# d1 END
|
|
23
|
+
# d END
|
|
24
|
+
# e START
|
|
25
|
+
# e1 START
|
|
26
|
+
# e1 END
|
|
27
|
+
# e END
|
|
28
|
+
|
|
29
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
30
|
+
require "keybreak"
|
|
31
|
+
|
|
32
|
+
RECORDS =<<EOD
|
|
33
|
+
a a1 1
|
|
34
|
+
b b1 2
|
|
35
|
+
b b2 3
|
|
36
|
+
c c1 4
|
|
37
|
+
c c1 5
|
|
38
|
+
c c2 6
|
|
39
|
+
d d1 7
|
|
40
|
+
e e1 8
|
|
41
|
+
e e1 9
|
|
42
|
+
EOD
|
|
43
|
+
|
|
44
|
+
c = Keybreak::Controller.new
|
|
45
|
+
sub_c = Keybreak::Controller.new
|
|
46
|
+
|
|
47
|
+
c.on(:keystart) {|key| puts "#{key} START"}.
|
|
48
|
+
on(:keyend) do |key|
|
|
49
|
+
sub_c.flush
|
|
50
|
+
puts "#{key} END"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
sub_c.on(:keystart) {|key| puts " #{key} START"}.
|
|
54
|
+
on(:keyend) {|key| puts " #{key} END" }
|
|
55
|
+
|
|
56
|
+
c.execute do
|
|
57
|
+
RECORDS.each_line do |line|
|
|
58
|
+
key, sub_key, value = line.split("\t")
|
|
59
|
+
feed(key)
|
|
60
|
+
sub_c.feed(sub_key)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# EOF
|
data/examples/nested_sum.rb
CHANGED
|
@@ -1,52 +1,55 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
# Print sum of values for each key and sub key
|
|
3
|
-
# =>
|
|
4
|
-
# a1:1
|
|
5
|
-
# total a:1
|
|
6
|
-
# b1:2
|
|
7
|
-
# b2:3
|
|
8
|
-
# total b:5
|
|
9
|
-
# c1:9
|
|
10
|
-
# c2:6
|
|
11
|
-
# total c:15
|
|
12
|
-
# d1:7
|
|
13
|
-
# total d:7
|
|
14
|
-
# e1:17
|
|
15
|
-
# total e:17
|
|
16
|
-
|
|
17
|
-
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
18
|
-
require "keybreak"
|
|
19
|
-
|
|
20
|
-
RECORDS =<<EOD
|
|
21
|
-
a a1 1
|
|
22
|
-
b b1 2
|
|
23
|
-
b b2 3
|
|
24
|
-
c c1 4
|
|
25
|
-
c c1 5
|
|
26
|
-
c c2 6
|
|
27
|
-
d d1 7
|
|
28
|
-
e e1 8
|
|
29
|
-
e e1 9
|
|
30
|
-
EOD
|
|
31
|
-
|
|
32
|
-
Keybreak.execute_with_controller do |c, sum|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print sum of values for each key and sub key
|
|
3
|
+
# =>
|
|
4
|
+
# a1:1
|
|
5
|
+
# total a:1
|
|
6
|
+
# b1:2
|
|
7
|
+
# b2:3
|
|
8
|
+
# total b:5
|
|
9
|
+
# c1:9
|
|
10
|
+
# c2:6
|
|
11
|
+
# total c:15
|
|
12
|
+
# d1:7
|
|
13
|
+
# total d:7
|
|
14
|
+
# e1:17
|
|
15
|
+
# total e:17
|
|
16
|
+
|
|
17
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
18
|
+
require "keybreak"
|
|
19
|
+
|
|
20
|
+
RECORDS =<<EOD
|
|
21
|
+
a a1 1
|
|
22
|
+
b b1 2
|
|
23
|
+
b b2 3
|
|
24
|
+
c c1 4
|
|
25
|
+
c c1 5
|
|
26
|
+
c c2 6
|
|
27
|
+
d d1 7
|
|
28
|
+
e e1 8
|
|
29
|
+
e e1 9
|
|
30
|
+
EOD
|
|
31
|
+
|
|
32
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
33
|
+
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
34
|
+
c.on(:keystart) {sum = 0}
|
|
35
|
+
c.on(:keyend) do |key|
|
|
36
|
+
sub_c.flush
|
|
37
|
+
puts "total #{key}:#{sum}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
41
|
+
sub_c.on(:keyend) do |key|
|
|
42
|
+
puts "#{key}:#{sub_sum}"
|
|
43
|
+
sum += sub_sum
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
RECORDS.each_line do |line|
|
|
47
|
+
key, sub_key, value = line.split("\t")
|
|
48
|
+
c.feed(key)
|
|
49
|
+
sub_c.feed(sub_key)
|
|
50
|
+
sub_sum += value.to_i
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# EOF
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print sum of values for each key and sub key
|
|
3
|
+
# =>
|
|
4
|
+
# a1:1
|
|
5
|
+
# total a:1
|
|
6
|
+
# b1:2
|
|
7
|
+
# b2:3
|
|
8
|
+
# total b:5
|
|
9
|
+
# c1:9
|
|
10
|
+
# c2:6
|
|
11
|
+
# total c:15
|
|
12
|
+
# d1:7
|
|
13
|
+
# total d:7
|
|
14
|
+
# e1:17
|
|
15
|
+
# total e:17
|
|
16
|
+
|
|
17
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
18
|
+
require "keybreak"
|
|
19
|
+
|
|
20
|
+
RECORDS =<<EOD
|
|
21
|
+
a a1 1
|
|
22
|
+
b b1 2
|
|
23
|
+
b b2 3
|
|
24
|
+
c c1 4
|
|
25
|
+
c c1 5
|
|
26
|
+
c c2 6
|
|
27
|
+
d d1 7
|
|
28
|
+
e e1 8
|
|
29
|
+
e e1 9
|
|
30
|
+
EOD
|
|
31
|
+
|
|
32
|
+
c = Keybreak::Controller.new
|
|
33
|
+
sub_c = Keybreak::Controller.new
|
|
34
|
+
|
|
35
|
+
sum = 0
|
|
36
|
+
c.on(:keystart) {sum = 0}
|
|
37
|
+
c.on(:keyend) do |key|
|
|
38
|
+
sub_c.flush
|
|
39
|
+
puts "total #{key}:#{sum}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
sub_sum = 0
|
|
43
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
44
|
+
sub_c.on(:keyend) do |key|
|
|
45
|
+
puts "#{key}:#{sub_sum}"
|
|
46
|
+
sum += sub_sum
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
c.execute do
|
|
50
|
+
RECORDS.each_line do |line|
|
|
51
|
+
key, sub_key, value = line.split("\t")
|
|
52
|
+
c.feed(key)
|
|
53
|
+
sub_c.feed(sub_key)
|
|
54
|
+
sub_sum += value.to_i
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# EOF
|
data/keybreak.gemspec
CHANGED
|
@@ -10,6 +10,7 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.email = ["nhashimoto01@gmail.com"]
|
|
11
11
|
|
|
12
12
|
spec.summary = %q{Keybreak is a utility module for key break processing in Ruby.}
|
|
13
|
+
spec.description = %q{Keybreak module may assist you to make your key break processing code simpler.}
|
|
13
14
|
spec.homepage = "https://github.com/hashimoton/keybreak"
|
|
14
15
|
spec.license = "MIT"
|
|
15
16
|
|
data/lib/keybreak/controller.rb
CHANGED
data/lib/keybreak/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keybreak
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- hashimoton
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -52,7 +52,8 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '3.0'
|
|
55
|
-
description:
|
|
55
|
+
description: Keybreak module may assist you to make your key break processing code
|
|
56
|
+
simpler.
|
|
56
57
|
email:
|
|
57
58
|
- nhashimoto01@gmail.com
|
|
58
59
|
executables: []
|
|
@@ -68,10 +69,13 @@ files:
|
|
|
68
69
|
- README.md
|
|
69
70
|
- Rakefile
|
|
70
71
|
- examples/count.rb
|
|
71
|
-
- examples/
|
|
72
|
+
- examples/empty_keys.rb
|
|
72
73
|
- examples/first_value.rb
|
|
73
74
|
- examples/last_value.rb
|
|
75
|
+
- examples/nested_keys.rb
|
|
76
|
+
- examples/nested_keys2.rb
|
|
74
77
|
- examples/nested_sum.rb
|
|
78
|
+
- examples/nested_sum2.rb
|
|
75
79
|
- examples/sum.rb
|
|
76
80
|
- keybreak.gemspec
|
|
77
81
|
- lib/keybreak.rb
|