kronk 1.6.2 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +29 -1
- data/Manifest.txt +6 -1
- data/README.rdoc +74 -28
- data/Rakefile +4 -3
- data/TODO.rdoc +7 -5
- data/bin/kronk +2 -11
- data/lib/kronk/async/em_ext.rb +34 -0
- data/lib/kronk/async/request.rb +73 -0
- data/lib/kronk/async/response.rb +70 -0
- data/lib/kronk/async.rb +118 -0
- data/lib/kronk/cmd.rb +111 -43
- data/lib/kronk/constants.rb +1 -0
- data/lib/kronk/core_ext.rb +1 -1
- data/lib/kronk/data_string.rb +251 -0
- data/lib/kronk/diff/output.rb +132 -100
- data/lib/kronk/diff.rb +20 -24
- data/lib/kronk/path/matcher.rb +8 -4
- data/lib/kronk/path/path_match.rb +48 -4
- data/lib/kronk/path/transaction.rb +74 -53
- data/lib/kronk/path.rb +11 -6
- data/lib/kronk/player/benchmark.rb +11 -12
- data/lib/kronk/player/input_reader.rb +40 -3
- data/lib/kronk/player/request_parser.rb +4 -1
- data/lib/kronk/player/stream.rb +2 -2
- data/lib/kronk/player/suite.rb +16 -9
- data/lib/kronk/player.rb +93 -143
- data/lib/kronk/queue_runner.rb +238 -0
- data/lib/kronk/request.rb +25 -20
- data/lib/kronk/response.rb +39 -10
- data/lib/kronk/test/assertions.rb +2 -2
- data/lib/kronk/test/helper_methods.rb +1 -1
- data/lib/kronk.rb +56 -24
- data/test/test_assertions.rb +4 -4
- data/test/test_cmd.rb +38 -10
- data/test/test_data_string.rb +242 -1
- data/test/test_diff.rb +8 -303
- data/test/test_helper.rb +1 -1
- data/test/test_kronk.rb +21 -28
- data/test/test_path.rb +29 -0
- data/test/test_path_match.rb +47 -2
- data/test/test_path_matcher.rb +42 -1
- data/test/test_player.rb +71 -72
- data/test/test_request.rb +31 -6
- data/test/test_request_parser.rb +7 -1
- data/test/test_response.rb +1 -1
- data/test/test_transaction.rb +78 -30
- metadata +64 -8
- data/lib/kronk/data_renderer.rb +0 -219
data/lib/kronk/diff/output.rb
CHANGED
@@ -1,41 +1,129 @@
|
|
1
1
|
class Kronk::Diff
|
2
2
|
|
3
|
+
##
|
4
|
+
# Renders diff outputs.
|
5
|
+
|
3
6
|
class Output
|
4
7
|
|
5
8
|
##
|
6
|
-
#
|
9
|
+
# Represents one diff section to render
|
10
|
+
# (starts with @@-line,len +line,len@@)
|
11
|
+
|
12
|
+
class Section
|
13
|
+
attr_accessor :context, :format, :lindex, :rindex, :llen, :rlen,
|
14
|
+
:lmeta, :rmeta
|
15
|
+
|
16
|
+
def initialize format, line_num_width=nil, lindex=0, rindex=0
|
17
|
+
@format = format
|
18
|
+
@cwidth = line_num_width
|
19
|
+
@lindex = lindex
|
20
|
+
@rindex = rindex
|
21
|
+
@llen = 0
|
22
|
+
@rlen = 0
|
23
|
+
@lmeta = nil
|
24
|
+
@rmeta = nil
|
25
|
+
@lines = []
|
26
|
+
@context = 0
|
27
|
+
end
|
7
28
|
|
8
|
-
def self.formatter name
|
9
|
-
return unless name
|
10
29
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
30
|
+
def add obj, meta=nil
|
31
|
+
@lmeta, @rmeta = meta if meta && !@lmeta && !@rmeta
|
32
|
+
@lmeta = ary_to_path @lmeta if Array === @rmeta
|
33
|
+
@rmeta = ary_to_path @rmeta if Array === @rmeta
|
34
|
+
|
35
|
+
if String === obj
|
36
|
+
add_common obj
|
37
|
+
|
38
|
+
elsif Array === obj
|
39
|
+
left, right = obj
|
40
|
+
left.each{|o| add_left o }
|
41
|
+
right.each{|o| add_right o }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def add_common obj
|
47
|
+
@llen += 1
|
48
|
+
@rlen += 1
|
49
|
+
@context += 1
|
50
|
+
|
51
|
+
line_nums =
|
52
|
+
@format.lines [@llen+@lindex, @rlen+@rindex], @cwidth if @cwidth
|
53
|
+
|
54
|
+
@lines << "#{line_nums}#{@format.common obj}"
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def add_left obj
|
59
|
+
@llen += 1
|
60
|
+
@context = 0
|
61
|
+
|
62
|
+
line_nums = @format.lines [@llen+@lindex, nil], @cwidth if @cwidth
|
63
|
+
@lines << "#{line_nums}#{@format.deleted obj}"
|
64
|
+
end
|
65
|
+
|
16
66
|
|
67
|
+
def add_right obj
|
68
|
+
@rlen += 1
|
69
|
+
@context = 0
|
70
|
+
|
71
|
+
line_nums = @format.lines [nil, @rlen+@rindex], @cwidth if @cwidth
|
72
|
+
@lines << "#{line_nums}#{@format.added obj}"
|
73
|
+
end
|
17
74
|
|
18
|
-
def self.attr_rm_cache *attrs # :nodoc:
|
19
|
-
self.send :attr_reader, *attrs
|
20
75
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
76
|
+
def ary_to_path ary
|
77
|
+
"#{Kronk::Path::DCH}#{Kronk::Path.join ary}"
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def render
|
82
|
+
cleft = "#{@lindex+1},#{@llen}"
|
83
|
+
cright = "#{@rindex+1},#{@rlen}"
|
84
|
+
|
85
|
+
if @lmeta != @rmeta && @lmeta && @rmeta
|
86
|
+
cleft << " " << @lmeta
|
87
|
+
cright << " " << @rmeta
|
88
|
+
else
|
89
|
+
info = @lmeta || @rmeta
|
27
90
|
end
|
91
|
+
|
92
|
+
[@format.context(cleft, cright, info), *@lines]
|
28
93
|
end
|
29
94
|
end
|
30
95
|
|
31
96
|
|
32
|
-
|
97
|
+
##
|
98
|
+
# Returns a formatter from a symbol or string. Returns nil if not found.
|
99
|
+
|
100
|
+
def self.formatter name
|
101
|
+
return unless name
|
102
|
+
|
103
|
+
return name if Class === name
|
104
|
+
return AsciiFormat if name.to_s =~ /^ascii(_diff)?$/
|
105
|
+
return ColorFormat if name.to_s =~ /^color(_diff)?$/
|
106
|
+
Kronk.find_const name
|
107
|
+
|
108
|
+
rescue NameError => e
|
109
|
+
raise Kronk::Exception, "No such formatter: #{name.inspect}"
|
110
|
+
end
|
33
111
|
|
34
112
|
|
113
|
+
attr_accessor :labels, :show_lines, :join_ch, :context, :format
|
114
|
+
|
115
|
+
|
116
|
+
##
|
117
|
+
# Create a new Kronk::Diff::Output instance.
|
118
|
+
# Options supported are:
|
119
|
+
# :context:: Integer - Number of context lines around diffs; default 3
|
120
|
+
# :diff_format:: String/Object - Formatter for the diff; default AsciiFormat
|
121
|
+
# :join_char:: String - Vharacter to join diff sections with; default \n
|
122
|
+
# :labels:: Array - Left and right names to display; default %w{left right}
|
123
|
+
# :show_lines:: Boolean - Show lines in diff; default false
|
124
|
+
|
35
125
|
def initialize diff, opts={}
|
36
|
-
@
|
37
|
-
@cached = nil
|
38
|
-
@diff = diff
|
126
|
+
@diff = diff
|
39
127
|
|
40
128
|
@format =
|
41
129
|
self.class.formatter(opts[:format] || Kronk.config[:diff_format]) ||
|
@@ -51,7 +139,7 @@ class Kronk::Diff
|
|
51
139
|
@labels[1] ||= "right"
|
52
140
|
|
53
141
|
@show_lines = opts[:show_lines] || Kronk.config[:show_lines]
|
54
|
-
@
|
142
|
+
@section = false
|
55
143
|
|
56
144
|
lines1 = diff.str1.lines.count
|
57
145
|
lines2 = diff.str2.lines.count
|
@@ -59,103 +147,47 @@ class Kronk::Diff
|
|
59
147
|
end
|
60
148
|
|
61
149
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
if !clen || next_diff
|
69
|
-
@record || [@output.length, line1+1, line2+1, 0, 0]
|
70
|
-
|
71
|
-
elsif @record && clen && !next_diff
|
72
|
-
scheck = @output.length - (clen - 1)
|
73
|
-
subary = @output[scheck..-1].to_a
|
74
|
-
|
75
|
-
if i == @diff_ary.length || !subary.find{|da| Array === da}
|
76
|
-
start = @record[0]
|
77
|
-
cleft = "#{@record[1]},#{@record[3]}"
|
78
|
-
cright = "#{@record[2]},#{@record[4]}"
|
150
|
+
def continue_section? i
|
151
|
+
!@context ||
|
152
|
+
!!@diff.diff_array[i,@context+1].to_a.find{|da| Array === da}
|
153
|
+
end
|
79
154
|
|
80
|
-
str = @output[start]
|
81
|
-
str = str[0][0] if Array === str
|
82
|
-
info = str.meta[0] if str.respond_to?(:meta)
|
83
155
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
info = nil
|
88
|
-
end
|
156
|
+
def start_section? i
|
157
|
+
!@section && continue_section?(i)
|
158
|
+
end
|
89
159
|
|
90
|
-
@output[start,0] = @format.context cleft, cright, info
|
91
|
-
false
|
92
160
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
else
|
98
|
-
@record
|
99
|
-
end
|
161
|
+
def end_section? i
|
162
|
+
@section &&
|
163
|
+
(i >= @diff.diff_array.length ||
|
164
|
+
!continue_section?(i) && @context && @section.context >= @context)
|
100
165
|
end
|
101
166
|
|
102
167
|
|
103
168
|
def render force=false
|
104
|
-
|
105
|
-
|
106
|
-
return @cached if !force && @cached
|
107
|
-
@output << @format.head(*@labels)
|
169
|
+
output = []
|
170
|
+
output << @format.head(*@labels)
|
108
171
|
|
109
172
|
line1 = line2 = 0
|
173
|
+
lwidth = @show_lines && @cwidth
|
110
174
|
|
111
|
-
|
112
|
-
|
113
|
-
@
|
114
|
-
|
115
|
-
case item
|
116
|
-
when String
|
117
|
-
line1 = line1.next
|
118
|
-
line2 = line2.next
|
119
|
-
@output << make_line(item, line1, line2) if @record
|
120
|
-
|
121
|
-
when Array
|
122
|
-
sides = [[],[]]
|
123
|
-
|
124
|
-
item[0].each do |ditem|
|
125
|
-
line1 = line1.next
|
126
|
-
sides[0] << make_line(ditem, line1, nil) if @record
|
127
|
-
end
|
175
|
+
@diff.diff_array.each_with_index do |item, i|
|
176
|
+
@section = Section.new @format, lwidth, line1, line2 if start_section? i
|
177
|
+
@section.add item, @diff.meta[i] if @section
|
128
178
|
|
129
|
-
|
130
|
-
|
131
|
-
sides[0] << make_line(ditem, nil, line2) if @record
|
132
|
-
end
|
179
|
+
line1 += Array === item ? item[0].length : 1
|
180
|
+
line2 += Array === item ? item[1].length : 1
|
133
181
|
|
134
|
-
|
182
|
+
if end_section?(i+1)
|
183
|
+
output.concat @section.render
|
184
|
+
@section = false
|
135
185
|
end
|
136
186
|
end
|
137
187
|
|
138
|
-
|
188
|
+
output.join(@join_ch)
|
139
189
|
end
|
140
190
|
|
141
191
|
alias to_s render
|
142
|
-
|
143
|
-
|
144
|
-
def make_line item, line1, line2
|
145
|
-
action = if line1 && !line2
|
146
|
-
:deleted
|
147
|
-
elsif !line1 && line2
|
148
|
-
:added
|
149
|
-
else
|
150
|
-
:common
|
151
|
-
end
|
152
|
-
|
153
|
-
lines = @format.lines [line1, line2], @cwidth if @show_lines
|
154
|
-
line = "#{lines}#{@format.send action, item}"
|
155
|
-
line = Kronk::DataString.new line, item.meta[0] if item.respond_to? :meta
|
156
|
-
@record[3] += 1 if line1
|
157
|
-
@record[4] += 1 if line2
|
158
|
-
line
|
159
|
-
end
|
160
192
|
end
|
161
193
|
end
|
data/lib/kronk/diff.rb
CHANGED
@@ -10,23 +10,8 @@ class Kronk
|
|
10
10
|
# Creates a new diff from two data objects.
|
11
11
|
|
12
12
|
def self.new_from_data data1, data2, opts={}
|
13
|
-
new
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
##
|
19
|
-
# Returns a data string that is diff-able, meaning sorted by
|
20
|
-
# Hash keys when available.
|
21
|
-
|
22
|
-
def self.ordered_data_string data, struct_only=false
|
23
|
-
data = Kronk::Path.pathed(data) if Kronk.config[:render_paths]
|
24
|
-
|
25
|
-
case Kronk.config[:render_lang].to_s
|
26
|
-
when 'ruby' then DataRenderer.ruby(data, struct_only)
|
27
|
-
else
|
28
|
-
DataRenderer.json(data, struct_only)
|
29
|
-
end
|
13
|
+
new DataString.new(data1, opts),
|
14
|
+
DataString.new(data2, opts), opts
|
30
15
|
end
|
31
16
|
|
32
17
|
|
@@ -47,13 +32,19 @@ class Kronk
|
|
47
32
|
end
|
48
33
|
|
49
34
|
|
50
|
-
attr_accessor :str1, :str2, :char, :output
|
35
|
+
attr_accessor :str1, :str2, :char, :output, :meta
|
36
|
+
|
37
|
+
##
|
38
|
+
# Create a new Diff instance from two strings.
|
39
|
+
# Options supported are those of Kronk::Diff::Output, plus:
|
40
|
+
# :char:: String/Regex - The char to split on for comparisons.
|
51
41
|
|
52
42
|
def initialize str1, str2, opts={}
|
53
43
|
@str1 = str1
|
54
44
|
@str2 = str2
|
55
45
|
@diff_ary = nil
|
56
46
|
@char = opts[:char] || /\r?\n/
|
47
|
+
@meta = []
|
57
48
|
@output = Output.new self, opts
|
58
49
|
end
|
59
50
|
|
@@ -71,7 +62,7 @@ class Kronk
|
|
71
62
|
|
72
63
|
def create_diff
|
73
64
|
diff_ary = []
|
74
|
-
return
|
65
|
+
return @str1.split @char if @str1 == @str2
|
75
66
|
|
76
67
|
arr1 = @str1.split @char
|
77
68
|
arr2 = @str2.split @char
|
@@ -90,15 +81,20 @@ class Kronk
|
|
90
81
|
right = arr2[last_i2...c[2]]
|
91
82
|
|
92
83
|
# add diffs
|
93
|
-
|
84
|
+
unless left.empty? && right.empty?
|
85
|
+
@meta << []
|
86
|
+
@meta.last[0] = left[0].meta[0] if left[0].respond_to?(:meta)
|
87
|
+
@meta.last[1] = right[0].meta[0] if right[0].respond_to?(:meta)
|
88
|
+
|
89
|
+
diff_ary << [left, right]
|
90
|
+
end
|
94
91
|
|
95
92
|
# add common
|
96
93
|
arr1[c[1], c[0]].each_with_index do |str1, i|
|
97
94
|
str2 = arr2[c[2]+i]
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
str1.meta[0] = [str1.meta[0], str2.meta[0]]
|
95
|
+
@meta << []
|
96
|
+
@meta.last[0] = str1.meta[0] if str1.respond_to?(:meta)
|
97
|
+
@meta.last[1] = str2.meta[0] if str2.respond_to?(:meta)
|
102
98
|
end
|
103
99
|
diff_ary.concat arr1[c[1], c[0]]
|
104
100
|
|
data/lib/kronk/path/matcher.rb
CHANGED
@@ -91,16 +91,20 @@ class Kronk::Path::Matcher
|
|
91
91
|
found, kmatch = match_node(@key, key) if @key
|
92
92
|
found, vmatch = match_node(@value, value) if @value && (!@key || found)
|
93
93
|
|
94
|
+
c_path.append_splat self, key if @recursive
|
95
|
+
|
94
96
|
if found
|
95
97
|
c_path.matches.concat kmatch.to_a
|
96
98
|
c_path.matches.concat vmatch.to_a
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
+
f_path = c_path.dup
|
101
|
+
f_path.splat[-1][-1].pop if @key && !f_path.splat.empty?
|
102
|
+
|
103
|
+
yield data, key, f_path if block_given?
|
104
|
+
paths << f_path
|
100
105
|
end
|
101
106
|
|
102
|
-
paths.concat
|
103
|
-
find_in(data[key], c_path, &block) if @recursive
|
107
|
+
paths.concat find_in(data[key], c_path, &block) if @recursive
|
104
108
|
end
|
105
109
|
|
106
110
|
paths
|
@@ -1,19 +1,30 @@
|
|
1
1
|
##
|
2
|
-
# Represents
|
2
|
+
# Represents the single match of a relative path against a data set.
|
3
3
|
|
4
4
|
class Kronk::Path::PathMatch < Array
|
5
5
|
|
6
|
-
attr_accessor :matches
|
6
|
+
attr_accessor :matches, :splat
|
7
7
|
|
8
8
|
def initialize *args
|
9
9
|
@matches = []
|
10
|
+
@splat = []
|
10
11
|
super
|
11
12
|
end
|
12
13
|
|
13
14
|
|
15
|
+
def append_splat id, key # :nodoc:
|
16
|
+
if @splat[-1] && @splat[-1][0] == id
|
17
|
+
@splat[-1][1] << key
|
18
|
+
else
|
19
|
+
@splat << [id, [key]]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
14
24
|
def dup # :nodoc:
|
15
25
|
path_match = super
|
16
26
|
path_match.matches = @matches.dup
|
27
|
+
path_match.splat = @splat.map{|key, sp| [key, sp.dup]}
|
17
28
|
path_match
|
18
29
|
end
|
19
30
|
|
@@ -29,9 +40,22 @@ class Kronk::Path::PathMatch < Array
|
|
29
40
|
|
30
41
|
|
31
42
|
##
|
32
|
-
# Builds a path array by replacing %n values with matches.
|
43
|
+
# Builds a path array by replacing %n and %% values with matches and splat.
|
44
|
+
#
|
45
|
+
# matches = Path.find_in "**/foo=bar", data
|
46
|
+
# # [["path", "to", "foo"]]
|
47
|
+
#
|
48
|
+
# matches.first.make_path "root/%%/foo"
|
49
|
+
# # ["root", "path", "to", "foo"]
|
50
|
+
#
|
51
|
+
# matches = Path.find_in "path/*/(foo)=bar", data
|
52
|
+
# # [["path", "to", "foo"]]
|
53
|
+
#
|
54
|
+
# matches.first.make_path "root/%1/%2"
|
55
|
+
# # ["root", "to", "foo"]
|
33
56
|
|
34
57
|
def make_path path_map, regex_opts=nil, &block
|
58
|
+
tmpsplat = @splat.dup
|
35
59
|
path = []
|
36
60
|
escape = false
|
37
61
|
replace = false
|
@@ -47,7 +71,27 @@ class Kronk::Path::PathMatch < Array
|
|
47
71
|
new_item = true
|
48
72
|
|
49
73
|
when Kronk::Path::RCH
|
50
|
-
replace
|
74
|
+
if replace
|
75
|
+
if rindex.empty?
|
76
|
+
unless tmpsplat.empty?
|
77
|
+
items = tmpsplat.shift[1].dup
|
78
|
+
if new_item
|
79
|
+
new_item = false
|
80
|
+
else
|
81
|
+
path[-1] = path[-1].dup << items.shift
|
82
|
+
end
|
83
|
+
path.concat items
|
84
|
+
end
|
85
|
+
replace = false
|
86
|
+
else
|
87
|
+
append_match_for(rindex, path)
|
88
|
+
rindex = ""
|
89
|
+
end
|
90
|
+
|
91
|
+
next
|
92
|
+
else
|
93
|
+
replace = true
|
94
|
+
end
|
51
95
|
end and next unless escape
|
52
96
|
|
53
97
|
if replace
|