kronk 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/History.rdoc +30 -2
- data/Manifest.txt +14 -0
- data/README.rdoc +5 -7
- data/Rakefile +88 -4
- data/bin/kronk +2 -1
- data/bin/yzma +13 -0
- data/lib/kronk.rb +112 -430
- data/lib/kronk/cmd.rb +469 -0
- data/lib/kronk/data_set.rb +38 -44
- data/lib/kronk/diff.rb +105 -112
- data/lib/kronk/diff/ascii_format.rb +35 -0
- data/lib/kronk/diff/color_format.rb +49 -0
- data/lib/kronk/request.rb +6 -6
- data/lib/kronk/test.rb +15 -0
- data/lib/kronk/test/assertions.rb +97 -0
- data/lib/kronk/test/core_ext.rb +65 -0
- data/lib/kronk/test/helper_methods.rb +86 -0
- data/lib/yzma.rb +174 -0
- data/lib/yzma/randomizer.rb +54 -0
- data/lib/yzma/report.rb +47 -0
- data/test/test_assertions.rb +93 -0
- data/test/test_core_ext.rb +74 -0
- data/test/test_data_set.rb +41 -32
- data/test/test_diff.rb +50 -24
- data/test/test_helper_methods.rb +177 -0
- data/test/test_kronk.rb +3 -1
- metadata +36 -19
data/lib/kronk/data_set.rb
CHANGED
@@ -19,22 +19,6 @@ class Kronk
|
|
19
19
|
end
|
20
20
|
|
21
21
|
|
22
|
-
##
|
23
|
-
# Retrieves the data at the given path array.
|
24
|
-
|
25
|
-
def data_at_path path
|
26
|
-
self.class.data_at_path @data, path
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
##
|
31
|
-
# Checks if data is available at the given path.
|
32
|
-
|
33
|
-
def data_at_path? path
|
34
|
-
self.class.data_at_path? @data, path
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
22
|
##
|
39
23
|
# Modify the data object by passing inclusive or exclusive data paths.
|
40
24
|
# Supports the following options:
|
@@ -85,6 +69,10 @@ class Kronk
|
|
85
69
|
new_curr_data[key] = curr_data[key]
|
86
70
|
break
|
87
71
|
|
72
|
+
elsif path.length == 1 && affect_parent
|
73
|
+
new_data = curr_data
|
74
|
+
break
|
75
|
+
|
88
76
|
else
|
89
77
|
new_curr_data[key] ||= curr_data[key].class.new
|
90
78
|
new_curr_data = new_curr_data[key]
|
@@ -106,6 +94,8 @@ class Kronk
|
|
106
94
|
find_data data_path do |obj, k, path|
|
107
95
|
|
108
96
|
if affect_parent && data_at_path?(path)
|
97
|
+
@data = @data.class.new and return if path.length == 1
|
98
|
+
|
109
99
|
parent_data = data_at_path path[0..-3]
|
110
100
|
del_method = Array === parent_data ? :delete_at : :delete
|
111
101
|
|
@@ -140,23 +130,16 @@ class Kronk
|
|
140
130
|
# # Returns an Array of grand-children key/value pairs
|
141
131
|
# # where the value is 'invalid' or blank
|
142
132
|
|
143
|
-
def find_data data_path, curr_path=nil, &block
|
144
|
-
self.class.find_data @data, data_path, curr_path, &block
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
##
|
149
|
-
# See DataSet#find_data
|
150
|
-
|
151
|
-
def self.find_data data, data_path, curr_path=nil, &block
|
133
|
+
def find_data data_path, curr_path=nil, data=nil, &block
|
152
134
|
curr_path ||= []
|
135
|
+
data ||= @data
|
153
136
|
|
154
137
|
key, value, rec, data_path = parse_data_path data_path
|
155
138
|
|
156
139
|
yield_data_points data, key, value, rec, curr_path do |d, k, p|
|
157
140
|
|
158
141
|
if data_path
|
159
|
-
find_data d[k],
|
142
|
+
find_data data_path, p, d[k], &block
|
160
143
|
else
|
161
144
|
yield d, k, p
|
162
145
|
end
|
@@ -167,8 +150,8 @@ class Kronk
|
|
167
150
|
##
|
168
151
|
# Checks if data is available at the given path.
|
169
152
|
|
170
|
-
def
|
171
|
-
data_at_path
|
153
|
+
def data_at_path? path
|
154
|
+
data_at_path path
|
172
155
|
true
|
173
156
|
|
174
157
|
rescue NoMethodError, TypeError
|
@@ -179,8 +162,8 @@ class Kronk
|
|
179
162
|
##
|
180
163
|
# Retrieve the data at the given path array location.
|
181
164
|
|
182
|
-
def
|
183
|
-
curr = data
|
165
|
+
def data_at_path path
|
166
|
+
curr = @data
|
184
167
|
path.each do |p|
|
185
168
|
raise TypeError, "Expected instance of Array or Hash" unless
|
186
169
|
Array === curr || Hash === curr
|
@@ -198,7 +181,7 @@ class Kronk
|
|
198
181
|
# - Recursive matching
|
199
182
|
# - New data path value
|
200
183
|
|
201
|
-
def
|
184
|
+
def parse_data_path data_path
|
202
185
|
data_path = data_path.dup
|
203
186
|
key = nil
|
204
187
|
value = nil
|
@@ -236,17 +219,22 @@ class Kronk
|
|
236
219
|
|
237
220
|
|
238
221
|
##
|
239
|
-
# Decide whether to make path item a regex or
|
222
|
+
# Decide whether to make path item a regex, range, array, or string.
|
240
223
|
|
241
|
-
def
|
224
|
+
def parse_path_item str
|
242
225
|
if str =~ /(^|[^\\])([\*\?\|])/
|
243
226
|
str.gsub!(/(^|[^\\])(\*|\?)/, '\1.\2')
|
244
|
-
|
227
|
+
/^(#{str})$/i
|
228
|
+
|
229
|
+
elsif str =~ %r{^(\-?\d+)(\.{2,3})(\-?\d+)$}
|
230
|
+
Range.new $1.to_i, $3.to_i, ($2 == "...")
|
231
|
+
|
232
|
+
elsif str =~ %r{^(\-?\d+),(\-?\d+)$}
|
233
|
+
Range.new $1.to_i, ($1.to_i + $2.to_i), true
|
234
|
+
|
245
235
|
else
|
246
|
-
str.gsub
|
236
|
+
str.gsub "\\", ""
|
247
237
|
end
|
248
|
-
|
249
|
-
str
|
250
238
|
end
|
251
239
|
|
252
240
|
|
@@ -254,7 +242,7 @@ class Kronk
|
|
254
242
|
# Yield data object and key, if a specific key or value matches
|
255
243
|
# the given data.
|
256
244
|
|
257
|
-
def
|
245
|
+
def yield_data_points data, mkey, mvalue=nil,
|
258
246
|
recursive=false, path=nil, &block
|
259
247
|
|
260
248
|
return unless Hash === data || Array === data
|
@@ -266,8 +254,6 @@ class Kronk
|
|
266
254
|
found = match_data_item(mkey, key) &&
|
267
255
|
match_data_item(mvalue, value)
|
268
256
|
|
269
|
-
#puts "Found: #{data.inspect} #{mkey.inspect} -> #{key.inspect}" if found
|
270
|
-
|
271
257
|
yield data, key, curr_path if found
|
272
258
|
yield_data_points data[key], mkey, mvalue, true, curr_path, &block if
|
273
259
|
recursive
|
@@ -278,15 +264,23 @@ class Kronk
|
|
278
264
|
##
|
279
265
|
# Check if data key or value is a match for nested data searches.
|
280
266
|
|
281
|
-
def
|
267
|
+
def match_data_item item1, item2
|
282
268
|
return if !item1.nil? && (Array === item2 || Hash === item2)
|
283
269
|
|
284
|
-
if
|
270
|
+
if item1.class == item2.class
|
271
|
+
item1 == item2
|
272
|
+
|
273
|
+
elsif Regexp === item1
|
285
274
|
item2.to_s =~ item1
|
275
|
+
|
276
|
+
elsif Range === item1
|
277
|
+
item1.include? item2.to_i
|
278
|
+
|
286
279
|
elsif item1.nil?
|
287
280
|
true
|
281
|
+
|
288
282
|
else
|
289
|
-
item2.to_s == item1.to_s
|
283
|
+
item2.to_s.downcase == item1.to_s.downcase
|
290
284
|
end
|
291
285
|
end
|
292
286
|
|
@@ -294,7 +288,7 @@ class Kronk
|
|
294
288
|
##
|
295
289
|
# Universal iterator for Hash and Array objects.
|
296
290
|
|
297
|
-
def
|
291
|
+
def each_data_item data, &block
|
298
292
|
case data
|
299
293
|
|
300
294
|
when Hash
|
data/lib/kronk/diff.rb
CHANGED
@@ -1,87 +1,11 @@
|
|
1
1
|
class Kronk
|
2
2
|
|
3
|
-
|
4
3
|
##
|
5
4
|
# Creates simple diffs as formatted strings or arrays, from two strings or
|
6
5
|
# data objects.
|
7
6
|
|
8
7
|
class Diff
|
9
8
|
|
10
|
-
##
|
11
|
-
# Format diff with ascii
|
12
|
-
|
13
|
-
class AsciiFormat
|
14
|
-
|
15
|
-
def self.lines line_nums, col_width
|
16
|
-
out =
|
17
|
-
[*line_nums].map do |lnum|
|
18
|
-
lnum.to_s.rjust col_width
|
19
|
-
end.join "|"
|
20
|
-
|
21
|
-
"#{out} "
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
def self.deleted str
|
26
|
-
"- #{str}"
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
def self.added str
|
31
|
-
"+ #{str}"
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
def self.common str
|
36
|
-
" #{str}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
##
|
42
|
-
# Format diff with ascii
|
43
|
-
|
44
|
-
class ColorFormat
|
45
|
-
|
46
|
-
def self.require_win_color
|
47
|
-
begin
|
48
|
-
require 'Win32/Console/ANSI'
|
49
|
-
rescue LoadError
|
50
|
-
puts "Warning: You must gem install win32console to use color"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
def self.lines line_nums, col_width
|
56
|
-
require_win_color if Kronk.windows?
|
57
|
-
|
58
|
-
out =
|
59
|
-
[*line_nums].map do |lnum|
|
60
|
-
lnum.to_s.rjust col_width
|
61
|
-
end.join "\033[32m"
|
62
|
-
|
63
|
-
"\033[7;31m#{out}\033[0m "
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
def self.deleted str
|
68
|
-
require_win_color if Kronk.windows?
|
69
|
-
"\033[31m#{str}\033[0m"
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
|
-
def self.added str
|
74
|
-
require_win_color if Kronk.windows?
|
75
|
-
"\033[32m#{str}\033[0m"
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
def self.common str
|
80
|
-
str
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
9
|
##
|
86
10
|
# Creates a new diff from two data objects.
|
87
11
|
|
@@ -184,69 +108,127 @@ class Kronk
|
|
184
108
|
|
185
109
|
def create_diff
|
186
110
|
diff_ary = []
|
187
|
-
sub_diff = nil
|
188
111
|
|
189
112
|
arr1 = @str1.split @char
|
190
113
|
arr2 = @str2.split @char
|
191
114
|
|
192
|
-
|
193
|
-
item1, item2 = arr1.shift, arr2.shift
|
115
|
+
common_list = find_common arr1, arr2
|
194
116
|
|
195
|
-
|
196
|
-
if sub_diff
|
197
|
-
diff_ary << sub_diff
|
198
|
-
sub_diff = nil
|
199
|
-
end
|
117
|
+
return [[arr1, arr2]] if common_list.empty?
|
200
118
|
|
201
|
-
|
202
|
-
|
203
|
-
end
|
119
|
+
last_i1 = 0
|
120
|
+
last_i2 = 0
|
204
121
|
|
205
|
-
|
206
|
-
|
122
|
+
common_list.each do |c|
|
123
|
+
next unless c
|
207
124
|
|
125
|
+
left = arr1[last_i1...c[1]]
|
126
|
+
right = arr2[last_i2...c[2]]
|
208
127
|
|
209
|
-
|
210
|
-
|
211
|
-
sub_diff = nil
|
128
|
+
# add diffs
|
129
|
+
diff_ary << [left, right] unless left.empty? && right.empty?
|
212
130
|
|
213
|
-
|
214
|
-
|
215
|
-
sub_diff = nil
|
131
|
+
# add common
|
132
|
+
diff_ary.concat arr1[c[1], c[0]]
|
216
133
|
|
217
|
-
|
218
|
-
|
219
|
-
sub_diff[0] << item1 if item1
|
220
|
-
sub_diff[1] << item2 if item2
|
221
|
-
end
|
134
|
+
last_i1 = c[1] + c[0]
|
135
|
+
last_i2 = c[2] + c[0]
|
222
136
|
end
|
223
137
|
|
224
|
-
|
138
|
+
left = arr1[last_i1..-1]
|
139
|
+
right = arr2[last_i2..-1]
|
140
|
+
|
141
|
+
diff_ary << [left, right] unless left.empty? && right.empty?
|
225
142
|
|
226
143
|
diff_ary
|
227
144
|
end
|
228
145
|
|
229
146
|
|
230
147
|
##
|
231
|
-
#
|
148
|
+
# Recursively finds common sequences between two arrays and returns
|
149
|
+
# them in the order they occur as an array of arrays:
|
150
|
+
# find_common arr1, arr2
|
151
|
+
# #=> [[size, arr1_index, arr2_index], [size, arr1_index, arr2_index],...]
|
152
|
+
|
153
|
+
def find_common arr1, arr2
|
154
|
+
used1 = []
|
155
|
+
used2 = []
|
156
|
+
|
157
|
+
common = []
|
232
158
|
|
233
|
-
|
234
|
-
|
159
|
+
common_sequences(arr1, arr2) do |seq|
|
160
|
+
next if used1[seq[1]] || used2[seq[2]]
|
161
|
+
|
162
|
+
next if used1[seq[1], seq[0]].to_a.index(true) ||
|
163
|
+
used2[seq[2], seq[0]].to_a.index(true)
|
164
|
+
|
165
|
+
next if used1[seq[1]+seq[0]..-1].to_a.nitems !=
|
166
|
+
used2[seq[2]+seq[0]..-1].to_a.nitems
|
167
|
+
|
168
|
+
|
169
|
+
used1.fill(true, seq[1], seq[0])
|
170
|
+
used2.fill(true, seq[2], seq[0])
|
171
|
+
|
172
|
+
common[seq[1]] = seq
|
173
|
+
end
|
174
|
+
|
175
|
+
common
|
235
176
|
end
|
236
177
|
|
237
178
|
|
238
179
|
##
|
239
|
-
#
|
180
|
+
# Returns all common sequences between to arrays ordered by sequence length
|
181
|
+
# according to the following format:
|
182
|
+
# [[[len1, ix, iy], [len1, ix, iy]],[[len2, ix, iy]]]
|
183
|
+
# # e.g.
|
184
|
+
# [nil,[[1,2,3],[1,2,5]],nil,[[3,4,5],[3,6,9]]
|
185
|
+
|
186
|
+
def common_sequences arr1, arr2, &block
|
187
|
+
sequences = []
|
188
|
+
|
189
|
+
arr2_map = {}
|
190
|
+
arr2.each_with_index do |line, j|
|
191
|
+
arr2_map[line] ||= []
|
192
|
+
arr2_map[line] << j
|
193
|
+
end
|
194
|
+
|
195
|
+
arr1.each_with_index do |line, i|
|
196
|
+
next unless arr2_map[line]
|
240
197
|
|
241
|
-
|
242
|
-
|
198
|
+
arr2_map[line].each do |j|
|
199
|
+
line1 = line
|
200
|
+
line2 = arr2[j]
|
243
201
|
|
244
|
-
|
245
|
-
|
246
|
-
added.concat arr.slice!(0..index) if index >= 0
|
202
|
+
k = i
|
203
|
+
start_j = j
|
247
204
|
|
248
|
-
|
249
|
-
|
205
|
+
while line1 && line1 == line2 && k < arr1.length
|
206
|
+
k += 1
|
207
|
+
j += 1
|
208
|
+
|
209
|
+
line1 = arr1[k]
|
210
|
+
line2 = arr2[j]
|
211
|
+
end
|
212
|
+
|
213
|
+
len = j - start_j
|
214
|
+
|
215
|
+
sequences[len] ||= []
|
216
|
+
sequences[len] << [len, i, start_j]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
yield_sequences sequences, &block if block_given?
|
221
|
+
|
222
|
+
sequences
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
def yield_sequences sequences, dist=0, &block
|
227
|
+
while sequences.length > dist
|
228
|
+
item = sequences.pop
|
229
|
+
next unless item
|
230
|
+
item.each &block
|
231
|
+
end
|
250
232
|
end
|
251
233
|
|
252
234
|
|
@@ -329,3 +311,14 @@ class Kronk
|
|
329
311
|
end
|
330
312
|
end
|
331
313
|
end
|
314
|
+
|
315
|
+
|
316
|
+
# For Ruby 1.9
|
317
|
+
|
318
|
+
unless [].respond_to? :nitems
|
319
|
+
class Array
|
320
|
+
def nitems
|
321
|
+
self.compact.length
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Kronk
|
2
|
+
|
3
|
+
class Diff
|
4
|
+
|
5
|
+
##
|
6
|
+
# Format diff with ascii
|
7
|
+
|
8
|
+
class AsciiFormat
|
9
|
+
|
10
|
+
def self.lines line_nums, col_width
|
11
|
+
out =
|
12
|
+
[*line_nums].map do |lnum|
|
13
|
+
lnum.to_s.rjust col_width
|
14
|
+
end.join "|"
|
15
|
+
|
16
|
+
"#{out} "
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def self.deleted str
|
21
|
+
"- #{str}"
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.added str
|
26
|
+
"+ #{str}"
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def self.common str
|
31
|
+
" #{str}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|