kronk 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/History.rdoc +29 -1
  2. data/Manifest.txt +6 -1
  3. data/README.rdoc +74 -28
  4. data/Rakefile +4 -3
  5. data/TODO.rdoc +7 -5
  6. data/bin/kronk +2 -11
  7. data/lib/kronk/async/em_ext.rb +34 -0
  8. data/lib/kronk/async/request.rb +73 -0
  9. data/lib/kronk/async/response.rb +70 -0
  10. data/lib/kronk/async.rb +118 -0
  11. data/lib/kronk/cmd.rb +111 -43
  12. data/lib/kronk/constants.rb +1 -0
  13. data/lib/kronk/core_ext.rb +1 -1
  14. data/lib/kronk/data_string.rb +251 -0
  15. data/lib/kronk/diff/output.rb +132 -100
  16. data/lib/kronk/diff.rb +20 -24
  17. data/lib/kronk/path/matcher.rb +8 -4
  18. data/lib/kronk/path/path_match.rb +48 -4
  19. data/lib/kronk/path/transaction.rb +74 -53
  20. data/lib/kronk/path.rb +11 -6
  21. data/lib/kronk/player/benchmark.rb +11 -12
  22. data/lib/kronk/player/input_reader.rb +40 -3
  23. data/lib/kronk/player/request_parser.rb +4 -1
  24. data/lib/kronk/player/stream.rb +2 -2
  25. data/lib/kronk/player/suite.rb +16 -9
  26. data/lib/kronk/player.rb +93 -143
  27. data/lib/kronk/queue_runner.rb +238 -0
  28. data/lib/kronk/request.rb +25 -20
  29. data/lib/kronk/response.rb +39 -10
  30. data/lib/kronk/test/assertions.rb +2 -2
  31. data/lib/kronk/test/helper_methods.rb +1 -1
  32. data/lib/kronk.rb +56 -24
  33. data/test/test_assertions.rb +4 -4
  34. data/test/test_cmd.rb +38 -10
  35. data/test/test_data_string.rb +242 -1
  36. data/test/test_diff.rb +8 -303
  37. data/test/test_helper.rb +1 -1
  38. data/test/test_kronk.rb +21 -28
  39. data/test/test_path.rb +29 -0
  40. data/test/test_path_match.rb +47 -2
  41. data/test/test_path_matcher.rb +42 -1
  42. data/test/test_player.rb +71 -72
  43. data/test/test_request.rb +31 -6
  44. data/test/test_request_parser.rb +7 -1
  45. data/test/test_response.rb +1 -1
  46. data/test/test_transaction.rb +78 -30
  47. metadata +64 -8
  48. data/lib/kronk/data_renderer.rb +0 -219
@@ -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
- # Returns a formatter from a symbol or string. Returns nil if not found.
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
- return name if Class === name
12
- return AsciiFormat if name == :ascii_diff
13
- return ColorFormat if name == :color_diff
14
- Kronk.find_const name rescue name
15
- end
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
- attrs.each do |attr|
22
- define_method "#{attr}=" do |value|
23
- if send(attr) != value
24
- instance_variable_set("@#{attr}", value)
25
- instance_variable_set("@cached", nil)
26
- end
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
- attr_rm_cache :labels, :show_lines, :join_ch, :context, :format, :diff_ary
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
- @output = []
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
- @record = false
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 record? i, line1, line2
63
- if @context
64
- clen = @context + 1
65
- next_diff = @diff_ary[i,clen].to_a.find{|da| Array === da}
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
- if Array === info && !info.empty?
85
- cleft << " " << info[0]
86
- cright << " " << info[1]
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
- else
94
- @record
95
- end
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
- self.diff_ary = @diff.diff_array
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
- 0.upto(@diff_ary.length) do |i|
112
- item = @diff_ary[i]
113
- @record = record? i, line1, line2
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
- item[1].each do |ditem|
130
- line2 = line2.next
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
- @output << sides if @record
182
+ if end_section?(i+1)
183
+ output.concat @section.render
184
+ @section = false
135
185
  end
136
186
  end
137
187
 
138
- @cached = @output.flatten.join(@join_ch)
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 ordered_data_string(data1, opts[:struct]),
14
- ordered_data_string(data2, opts[:struct]), opts
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 diff_ary if @str1.empty? && @str2.empty?
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
- diff_ary << [left, right] unless left.empty? && right.empty?
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
- next unless str1.respond_to?(:meta) && str2.respond_to?(:meta) &&
99
- str1.meta.first != str2.meta.first
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
 
@@ -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
- yield data, key, c_path if block_given?
99
- paths << c_path
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 a single match of a relative path against a data set.
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 = true
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