kronk 1.6.2 → 1.7.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.
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