keybreak 0.1.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 +15 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +292 -0
- data/Rakefile +7 -0
- data/examples/count.rb +33 -0
- data/examples/first_value.rb +31 -0
- data/examples/last_value.rb +31 -0
- data/examples/nested_sum.rb +49 -0
- data/examples/sum.rb +33 -0
- data/keybreak.gemspec +24 -0
- data/lib/keybreak/controller.rb +80 -0
- data/lib/keybreak/version.rb +5 -0
- data/lib/keybreak.rb +20 -0
- metadata +102 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
!binary "U0hBMQ==":
|
|
3
|
+
metadata.gz: !binary |-
|
|
4
|
+
OWE2ZTc3ZjI0YzBkZTZhNmMzMTBkMGYzNGY3OTFlMmQ1NTdjY2RiZQ==
|
|
5
|
+
data.tar.gz: !binary |-
|
|
6
|
+
Y2QyMmE5MzllY2MyOTRkNGY2ZWZhYTU4ODc0NGI1MTgwYjNlNWI3Ng==
|
|
7
|
+
SHA512:
|
|
8
|
+
metadata.gz: !binary |-
|
|
9
|
+
ZGI3MjdiZTc2YzgyMzg3Zjg5NjhiNGU2NTNiNGI4NWVmMTI3MjlhZDZlNjI0
|
|
10
|
+
MGY1NzU3YmZkMGE2MGE2ZmQ4NTk5MzRhN2IzNmIwYWU1MjBjY2YxYzA5YmY3
|
|
11
|
+
YjM5YzAzNTFkODhjMGZmMmQzMWU0YTI2NzhlNzRjNzVmODNkY2E=
|
|
12
|
+
data.tar.gz: !binary |-
|
|
13
|
+
ZjAwOWZmNzRhMzhkNjY2MzJjNmQwM2M1NzgzYWZiNzA0MDM0MWU1NTFlYmEy
|
|
14
|
+
NmE2NTMyMGMyMzRiOTEzYmQ4YjQ5NWZjMWNmYjJjYWI4NmZlMjM3MzM3NGE5
|
|
15
|
+
ZWE0ZTNmYzU4MGE1ZDQzZmFjZTM0MTQ4MTJhZGRkNzVkY2IwYjA=
|
data/.gitignore
ADDED
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--format documentation
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 hashimoton
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
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 column based records which can be grouped by a column,
|
|
10
|
+
doing the same process for each group.
|
|
11
|
+
The column used for the grouping is a "key".
|
|
12
|
+
In processing the record sequence, when the key's value in a record changes from the previous record,
|
|
13
|
+
it is called "key break".
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Motivation
|
|
17
|
+
|
|
18
|
+
A typical key break processing is counting the number of records for each key like below:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
count = 0
|
|
22
|
+
prev_key = nil
|
|
23
|
+
|
|
24
|
+
DATA.each do |line|
|
|
25
|
+
key = line.chomp.split("\t")[0]
|
|
26
|
+
|
|
27
|
+
if !prev_key.nil? && key != prev_key
|
|
28
|
+
puts "#{prev_key}:#{count}"
|
|
29
|
+
count = 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
count += 1
|
|
33
|
+
prev_key = key
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if !prev_key.nil?
|
|
37
|
+
puts "#{prev_key}:#{count}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
__END__
|
|
41
|
+
a 1
|
|
42
|
+
b 2
|
|
43
|
+
b 3
|
|
44
|
+
c 4
|
|
45
|
+
c 5
|
|
46
|
+
c 6
|
|
47
|
+
d 7
|
|
48
|
+
e 8
|
|
49
|
+
e 9
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Note that you have to write "puts" once again after the iteration.
|
|
53
|
+
This is quite troublesome even for such a simple task, and is very my motivation.
|
|
54
|
+
|
|
55
|
+
With Keybreak module, the code is like below:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
require "keybreak"
|
|
59
|
+
|
|
60
|
+
Keybreak.execute_with_controller do |c, count|
|
|
61
|
+
c.on(:keystart) {count = 0}
|
|
62
|
+
c.on(:keyend) {|key| puts "#{key}:#{count}"}
|
|
63
|
+
|
|
64
|
+
DATA.each do |line|
|
|
65
|
+
key = line.chomp.split("\t")[0]
|
|
66
|
+
c.feed(key)
|
|
67
|
+
count += 1
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
__END__
|
|
72
|
+
a 1
|
|
73
|
+
b 2
|
|
74
|
+
b 3
|
|
75
|
+
c 4
|
|
76
|
+
c 5
|
|
77
|
+
c 6
|
|
78
|
+
d 7
|
|
79
|
+
e 8
|
|
80
|
+
e 9
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
You need to register event handlers as a key break consists of two events:
|
|
84
|
+
First, the end of current key sequence (:keyend).
|
|
85
|
+
Next, the start of new key sequence (:keystart).
|
|
86
|
+
|
|
87
|
+
Then call feed() in your record loop.
|
|
88
|
+
The method holds current key, detects a key break, and calls the event handlers accordingly.
|
|
89
|
+
The block given to execute_with_controller makes sure to process the end of the last key.
|
|
90
|
+
|
|
91
|
+
In many cases, taking a functional approach such as Enumerable#map achieves the task simply.
|
|
92
|
+
But sometimes, a procedural code is needed.
|
|
93
|
+
Keybreak module may assist you to make your key break code simpler.
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Installation
|
|
97
|
+
|
|
98
|
+
Add this line to your application's Gemfile:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
gem 'keybreak'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
And then execute:
|
|
105
|
+
|
|
106
|
+
$ bundle
|
|
107
|
+
|
|
108
|
+
Or install it yourself as:
|
|
109
|
+
|
|
110
|
+
$ gem install keybreak
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
In your ruby source, write the line below:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
require "keybreak"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Here are some examples of typical key break processing.
|
|
122
|
+
See [examples](https://github.com/hashimoton/keybreak/tree/master/examples) for full code.
|
|
123
|
+
|
|
124
|
+
### Print first values for each key
|
|
125
|
+
|
|
126
|
+
Register a keystart handler which prints the given key and value.
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
Keybreak.execute_with_controller do |c|
|
|
130
|
+
c.on(:keystart) {|key, value| puts "#{key}:#{value}"}
|
|
131
|
+
|
|
132
|
+
DATA.each do |line|
|
|
133
|
+
key, value = line.chomp.split("\t")
|
|
134
|
+
c.feed(key, value)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
__END__
|
|
139
|
+
a 1
|
|
140
|
+
b 2
|
|
141
|
+
b 3
|
|
142
|
+
c 4
|
|
143
|
+
c 5
|
|
144
|
+
c 6
|
|
145
|
+
d 7
|
|
146
|
+
e 8
|
|
147
|
+
e 9
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The result will be:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
a:1
|
|
154
|
+
b:2
|
|
155
|
+
c:4
|
|
156
|
+
d:7
|
|
157
|
+
e:8
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Print last values for each key
|
|
161
|
+
|
|
162
|
+
Borrows DATA from above example.
|
|
163
|
+
Register a keyend handler which prints the given key and value.
|
|
164
|
+
|
|
165
|
+
```ruby
|
|
166
|
+
Keybreak.execute_with_controller do |c|
|
|
167
|
+
c.on(:keyend) {|key, value| puts "#{key}:#{value}"}
|
|
168
|
+
|
|
169
|
+
DATA.each do |line|
|
|
170
|
+
key, value = line.chomp.split("\t")
|
|
171
|
+
c.feed(key, value)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The result will be:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
a:1
|
|
180
|
+
b:3
|
|
181
|
+
c:6
|
|
182
|
+
d:7
|
|
183
|
+
e:9
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Print sum of values for each key
|
|
187
|
+
|
|
188
|
+
Clear sum when a key starts.
|
|
189
|
+
Print sum when the key ends.
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
193
|
+
c.on(:keystart) {sum = 0}
|
|
194
|
+
c.on(:keyend) {|key| puts "#{key}:#{sum}"}
|
|
195
|
+
|
|
196
|
+
DATA.each do |line|
|
|
197
|
+
key, value = line.chomp.split("\t")
|
|
198
|
+
c.feed(key)
|
|
199
|
+
sum += value.to_i
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The result will be:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
a:1
|
|
208
|
+
b:5
|
|
209
|
+
c:15
|
|
210
|
+
d:7
|
|
211
|
+
e:17
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### Print sum of values for each key and sub key
|
|
216
|
+
|
|
217
|
+
Nest Keybreak.execute_with_controller.
|
|
218
|
+
Give sub key handlers a set of primary key and sub key (an array for instance)
|
|
219
|
+
so that a primary key break is also detected as a sub key break.
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
223
|
+
c.on(:keystart) {sum = 0}
|
|
224
|
+
c.on(:keyend) {|key| puts "total #{key}:#{sum}"}
|
|
225
|
+
|
|
226
|
+
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
227
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
228
|
+
sub_c.on(:keyend) do |keys|
|
|
229
|
+
puts "#{keys[1]}:#{sub_sum}"
|
|
230
|
+
sum += sub_sum
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
DATA.each do |line|
|
|
234
|
+
key, sub_key, value = line.chomp.split("\t")
|
|
235
|
+
sub_c.feed([key, sub_key])
|
|
236
|
+
c.feed(key)
|
|
237
|
+
sub_sum += value.to_i
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
__END__
|
|
243
|
+
a a1 1
|
|
244
|
+
b b1 2
|
|
245
|
+
b b2 3
|
|
246
|
+
c c1 4
|
|
247
|
+
c c1 5
|
|
248
|
+
c c2 6
|
|
249
|
+
d d1 7
|
|
250
|
+
e e1 8
|
|
251
|
+
e e1 9
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The result will be:
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
a1:1
|
|
258
|
+
total a:1
|
|
259
|
+
b1:2
|
|
260
|
+
b2:3
|
|
261
|
+
total b:5
|
|
262
|
+
c1:9
|
|
263
|
+
c2:6
|
|
264
|
+
total c:15
|
|
265
|
+
d1:7
|
|
266
|
+
total d:7
|
|
267
|
+
e1:17
|
|
268
|
+
total e:17
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Development
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
### Test
|
|
275
|
+
|
|
276
|
+
Run the tests in spec directory:
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
$ cd keybreak
|
|
280
|
+
$ rake spec
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
## Contributing
|
|
285
|
+
|
|
286
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hashimoton/keybreak.
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
292
|
+
|
data/Rakefile
ADDED
data/examples/count.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print number of each key
|
|
3
|
+
# =>
|
|
4
|
+
# a:1
|
|
5
|
+
# b:2
|
|
6
|
+
# c:3
|
|
7
|
+
# d:1
|
|
8
|
+
# e:2
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
11
|
+
require "keybreak"
|
|
12
|
+
|
|
13
|
+
Keybreak.execute_with_controller do |c, count|
|
|
14
|
+
c.on(:keystart) {count = 0}
|
|
15
|
+
c.on(:keyend) {|key| puts "#{key}:#{count}"}
|
|
16
|
+
|
|
17
|
+
DATA.each do |line|
|
|
18
|
+
key = line.chomp.split("\t")[0]
|
|
19
|
+
c.feed(key)
|
|
20
|
+
count += 1
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
__END__
|
|
25
|
+
a 1
|
|
26
|
+
b 2
|
|
27
|
+
b 3
|
|
28
|
+
c 4
|
|
29
|
+
c 5
|
|
30
|
+
c 6
|
|
31
|
+
d 7
|
|
32
|
+
e 8
|
|
33
|
+
e 9
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print first values for each key
|
|
3
|
+
# =>
|
|
4
|
+
# a:1
|
|
5
|
+
# b:2
|
|
6
|
+
# c:4
|
|
7
|
+
# d:7
|
|
8
|
+
# e:8
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
11
|
+
require "keybreak"
|
|
12
|
+
|
|
13
|
+
Keybreak.execute_with_controller do |c|
|
|
14
|
+
c.on(:keystart) {|key, value| puts "#{key}:#{value}"}
|
|
15
|
+
|
|
16
|
+
DATA.each do |line|
|
|
17
|
+
key, value = line.chomp.split("\t")
|
|
18
|
+
c.feed(key, value)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
__END__
|
|
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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print last values for each key
|
|
3
|
+
# =>
|
|
4
|
+
# a:1
|
|
5
|
+
# b:3
|
|
6
|
+
# c:6
|
|
7
|
+
# d:7
|
|
8
|
+
# e:9
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
11
|
+
require "keybreak"
|
|
12
|
+
|
|
13
|
+
Keybreak.execute_with_controller do |c|
|
|
14
|
+
c.on(:keyend) {|key, value| puts "#{key}:#{value}"}
|
|
15
|
+
|
|
16
|
+
DATA.each do |line|
|
|
17
|
+
key, value = line.chomp.split("\t")
|
|
18
|
+
c.feed(key, value)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
__END__
|
|
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
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
21
|
+
c.on(:keystart) {sum = 0}
|
|
22
|
+
c.on(:keyend) {|key| puts "total #{key}:#{sum}"}
|
|
23
|
+
|
|
24
|
+
Keybreak.execute_with_controller do |sub_c, sub_sum|
|
|
25
|
+
sub_c.on(:keystart) {sub_sum = 0}
|
|
26
|
+
sub_c.on(:keyend) do |keys|
|
|
27
|
+
puts "#{keys[1]}:#{sub_sum}"
|
|
28
|
+
sum += sub_sum
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
DATA.each do |line|
|
|
32
|
+
key, sub_key, value = line.chomp.split("\t")
|
|
33
|
+
sub_c.feed([key, sub_key])
|
|
34
|
+
c.feed(key)
|
|
35
|
+
sub_sum += value.to_i
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
__END__
|
|
41
|
+
a a1 1
|
|
42
|
+
b b1 2
|
|
43
|
+
b b2 3
|
|
44
|
+
c c1 4
|
|
45
|
+
c c1 5
|
|
46
|
+
c c2 6
|
|
47
|
+
d d1 7
|
|
48
|
+
e e1 8
|
|
49
|
+
e e1 9
|
data/examples/sum.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Print sum of values for each key
|
|
3
|
+
# =>
|
|
4
|
+
# a:1
|
|
5
|
+
# b:5
|
|
6
|
+
# c:15
|
|
7
|
+
# d:7
|
|
8
|
+
# e:17
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
11
|
+
require "keybreak"
|
|
12
|
+
|
|
13
|
+
Keybreak.execute_with_controller do |c, sum|
|
|
14
|
+
c.on(:keystart) {sum = 0}
|
|
15
|
+
c.on(:keyend) {|key| puts "#{key}:#{sum}"}
|
|
16
|
+
|
|
17
|
+
DATA.each do |line|
|
|
18
|
+
key, value = line.chomp.split("\t")
|
|
19
|
+
c.feed(key)
|
|
20
|
+
sum += value.to_i
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
__END__
|
|
25
|
+
a 1
|
|
26
|
+
b 2
|
|
27
|
+
b 3
|
|
28
|
+
c 4
|
|
29
|
+
c 5
|
|
30
|
+
c 6
|
|
31
|
+
d 7
|
|
32
|
+
e 8
|
|
33
|
+
e 9
|
data/keybreak.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'keybreak/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "keybreak"
|
|
8
|
+
spec.version = Keybreak::VERSION
|
|
9
|
+
spec.authors = ["hashimoton"]
|
|
10
|
+
spec.email = ["nhashimoto01@gmail.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{Keybreak is a utility module for key break processing in Ruby.}
|
|
13
|
+
spec.homepage = "https://github.com/hashimoton/keybreak"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
|
+
spec.bindir = "exe"
|
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
24
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
module Keybreak
|
|
4
|
+
|
|
5
|
+
# Controller of keybreak processing
|
|
6
|
+
class Controller
|
|
7
|
+
|
|
8
|
+
# Generate an instance
|
|
9
|
+
def initialize()
|
|
10
|
+
clear
|
|
11
|
+
@handlers = {}
|
|
12
|
+
@handlers[:keystart] = DO_NOTHING
|
|
13
|
+
@handlers[:keyend] = DO_NOTHING
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Registers the given block as a keybreak event handler
|
|
18
|
+
# Valid keybreak events are:
|
|
19
|
+
# :keystart
|
|
20
|
+
# :keyend
|
|
21
|
+
def on(event, &block)
|
|
22
|
+
@handlers[event] = block
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Detects keybreak and calls the registered handlers
|
|
27
|
+
# When a new key comes, call the keyend handler with the last key and value,
|
|
28
|
+
# then call the keystart handler with the new key and value
|
|
29
|
+
# For the first key feed, does not call the keyend handler
|
|
30
|
+
# Use flush() to call the keyend handler for the last fed key
|
|
31
|
+
def feed(key, *values)
|
|
32
|
+
if @is_fed
|
|
33
|
+
if key != @key
|
|
34
|
+
@handlers[:keyend].call(@key, *@values)
|
|
35
|
+
@key = key
|
|
36
|
+
@handlers[:keystart].call(key, *values)
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
@is_fed = true
|
|
40
|
+
@key = key
|
|
41
|
+
@handlers[:keystart].call(key, *values)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@values = values
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Clears internal data to the status before key feed starts
|
|
49
|
+
def clear()
|
|
50
|
+
@is_fed = false
|
|
51
|
+
@values = []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Calls the keyend handler once with the last fed key and value,
|
|
56
|
+
# then clears internal data to the status before key feed starts
|
|
57
|
+
# Place this method after the last feed() to complete keybreak process
|
|
58
|
+
# Does nothing when no key has been fed
|
|
59
|
+
def flush()
|
|
60
|
+
if @is_fed
|
|
61
|
+
@handlers[:keyend].call(@key, *@values)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
clear
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Executes the given block and calls flush() finally
|
|
69
|
+
# Place feed() within the block so that the keybreak handlers are
|
|
70
|
+
# called for all keys including the last key
|
|
71
|
+
def execute(&block)
|
|
72
|
+
instance_eval(&block)
|
|
73
|
+
self.flush
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end # class
|
|
77
|
+
|
|
78
|
+
end # module
|
|
79
|
+
|
|
80
|
+
# EOF
|
data/lib/keybreak.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
require "keybreak/version"
|
|
3
|
+
require "keybreak/controller"
|
|
4
|
+
|
|
5
|
+
# Utilities for keybreak (control-break) processing
|
|
6
|
+
module Keybreak
|
|
7
|
+
|
|
8
|
+
# The block which does nothing
|
|
9
|
+
DO_NOTHING = Proc.new {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Executes the given block with a Controller instance
|
|
13
|
+
# Within the block, register your keybreak handlers and feed keys from your data
|
|
14
|
+
# Then the handlers will be called for all keys including the last key
|
|
15
|
+
def execute_with_controller(&block)
|
|
16
|
+
Controller.new.execute(&block)
|
|
17
|
+
end
|
|
18
|
+
module_function :execute_with_controller
|
|
19
|
+
|
|
20
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: keybreak
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- hashimoton
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.11'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.11'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ~>
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description:
|
|
56
|
+
email:
|
|
57
|
+
- nhashimoto01@gmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- .gitignore
|
|
63
|
+
- .rspec
|
|
64
|
+
- .travis.yml
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- examples/count.rb
|
|
70
|
+
- examples/first_value.rb
|
|
71
|
+
- examples/last_value.rb
|
|
72
|
+
- examples/nested_sum.rb
|
|
73
|
+
- examples/sum.rb
|
|
74
|
+
- keybreak.gemspec
|
|
75
|
+
- lib/keybreak.rb
|
|
76
|
+
- lib/keybreak/controller.rb
|
|
77
|
+
- lib/keybreak/version.rb
|
|
78
|
+
homepage: https://github.com/hashimoton/keybreak
|
|
79
|
+
licenses:
|
|
80
|
+
- MIT
|
|
81
|
+
metadata: {}
|
|
82
|
+
post_install_message:
|
|
83
|
+
rdoc_options: []
|
|
84
|
+
require_paths:
|
|
85
|
+
- lib
|
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ! '>='
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ! '>='
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
requirements: []
|
|
97
|
+
rubyforge_project:
|
|
98
|
+
rubygems_version: 2.5.1
|
|
99
|
+
signing_key:
|
|
100
|
+
specification_version: 4
|
|
101
|
+
summary: Keybreak is a utility module for key break processing in Ruby.
|
|
102
|
+
test_files: []
|