piglet 0.1.1 → 0.1.2

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 (72) hide show
  1. data/README.rdoc +24 -4
  2. data/lib/piglet/field/binary_conditional.rb +15 -0
  3. data/lib/piglet/field/call_expression.rb +21 -0
  4. data/lib/piglet/field/infix_expression.rb +19 -0
  5. data/lib/piglet/field/literal.rb +20 -0
  6. data/lib/piglet/field/operators.rb +80 -0
  7. data/lib/piglet/field/prefix_expression.rb +23 -0
  8. data/lib/piglet/field/reference.rb +41 -0
  9. data/lib/piglet/field/rename.rb +13 -0
  10. data/lib/piglet/field/suffix_expression.rb +19 -0
  11. data/lib/piglet/inout/describe.rb +7 -0
  12. data/lib/piglet/inout/dump.rb +7 -0
  13. data/lib/piglet/inout/explain.rb +15 -0
  14. data/lib/piglet/inout/illustrate.rb +7 -0
  15. data/lib/piglet/inout/load.rb +31 -0
  16. data/lib/piglet/inout/output.rb +15 -0
  17. data/lib/piglet/inout/storage_types.rb +18 -0
  18. data/lib/piglet/inout/store.rb +19 -0
  19. data/lib/piglet/interpreter.rb +39 -7
  20. data/lib/piglet/relation/cogroup.rb +33 -0
  21. data/lib/piglet/relation/cross.rb +24 -0
  22. data/lib/piglet/relation/distinct.rb +18 -0
  23. data/lib/piglet/relation/filter.rb +15 -0
  24. data/lib/piglet/relation/foreach.rb +21 -0
  25. data/lib/piglet/relation/group.rb +23 -0
  26. data/lib/piglet/relation/join.rb +22 -0
  27. data/lib/piglet/relation/limit.rb +15 -0
  28. data/lib/piglet/relation/order.rb +31 -0
  29. data/lib/piglet/relation/relation.rb +179 -0
  30. data/lib/piglet/relation/sample.rb +15 -0
  31. data/lib/piglet/relation/split.rb +45 -0
  32. data/lib/piglet/relation/stream.rb +7 -0
  33. data/lib/piglet/relation/union.rb +21 -0
  34. data/lib/piglet.rb +40 -38
  35. data/spec/piglet/{field_spec.rb → field/reference_spec.rb} +22 -6
  36. data/spec/piglet/interpreter_spec.rb +51 -5
  37. data/spec/piglet/{relation_spec.rb → relation/relation_spec.rb} +6 -6
  38. data/spec/piglet/{split_spec.rb → relation/split_spec.rb} +8 -8
  39. data/spec/spec_helper.rb +0 -2
  40. metadata +39 -40
  41. data/examples/spike1.rb +0 -43
  42. data/examples/spike2.rb +0 -40
  43. data/lib/piglet/assignment.rb +0 -13
  44. data/lib/piglet/cogroup.rb +0 -31
  45. data/lib/piglet/cross.rb +0 -22
  46. data/lib/piglet/describe.rb +0 -5
  47. data/lib/piglet/distinct.rb +0 -16
  48. data/lib/piglet/dump.rb +0 -5
  49. data/lib/piglet/explain.rb +0 -13
  50. data/lib/piglet/field.rb +0 -40
  51. data/lib/piglet/field_expression_functions.rb +0 -62
  52. data/lib/piglet/field_function_expression.rb +0 -19
  53. data/lib/piglet/field_infix_expression.rb +0 -17
  54. data/lib/piglet/field_prefix_expression.rb +0 -21
  55. data/lib/piglet/field_rename.rb +0 -11
  56. data/lib/piglet/field_suffix_expression.rb +0 -17
  57. data/lib/piglet/filter.rb +0 -13
  58. data/lib/piglet/foreach.rb +0 -19
  59. data/lib/piglet/group.rb +0 -21
  60. data/lib/piglet/illustrate.rb +0 -5
  61. data/lib/piglet/join.rb +0 -20
  62. data/lib/piglet/limit.rb +0 -13
  63. data/lib/piglet/load.rb +0 -31
  64. data/lib/piglet/load_and_store.rb +0 -16
  65. data/lib/piglet/order.rb +0 -29
  66. data/lib/piglet/relation.rb +0 -177
  67. data/lib/piglet/sample.rb +0 -13
  68. data/lib/piglet/split.rb +0 -41
  69. data/lib/piglet/store.rb +0 -17
  70. data/lib/piglet/storing.rb +0 -13
  71. data/lib/piglet/stream.rb +0 -5
  72. data/lib/piglet/union.rb +0 -19
@@ -0,0 +1,22 @@
1
+ module Piglet
2
+ module Relation
3
+ class Join # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(relation, description)
7
+ @join_fields = Hash[*description.select { |k, v| k.is_a?(Relation) }.flatten]
8
+ @sources = @join_fields.keys
9
+ @using = description[:using]
10
+ @parallel = description[:parallel]
11
+ end
12
+
13
+ def to_s
14
+ joins = @sources.map { |s| "#{s.alias} BY #{@join_fields[s]}" }.join(', ')
15
+ str = "JOIN #{joins}"
16
+ str << " USING \"#{@using.to_s}\"" if @using
17
+ str << " PARALLEL #{@parallel}" if @parallel
18
+ str
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Piglet
2
+ module Relation
3
+ class Limit # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(relation, n)
7
+ @sources, @n = [relation], n
8
+ end
9
+
10
+ def to_s
11
+ "LIMIT #{@sources.first.alias} #{@n}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Piglet
2
+ module Relation
3
+ class Order # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(relation, fields, options)
7
+ options ||= {}
8
+ @sources, @parallel = [relation], options[:parallel]
9
+ @fields = fields.is_a?(Enumerable) ? fields : [fields]
10
+ end
11
+
12
+ def to_s
13
+ "ORDER #{@sources.first.alias} BY #{field_strings}"
14
+ end
15
+
16
+ private
17
+
18
+ def field_strings
19
+ @fields.map { |f| field_string(f) }.join(', ')
20
+ end
21
+
22
+ def field_string(f)
23
+ if f.is_a?(Enumerable)
24
+ "#{f[0]} #{f[1].to_s.upcase}"
25
+ else
26
+ f.to_s
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,179 @@
1
+ module Piglet
2
+ module Relation
3
+ module Relation
4
+ attr_reader :sources
5
+
6
+ # The name this relation will get in Pig Latin. Then name is generated when
7
+ # the relation is outputed by the interpreter, and will be unique.
8
+ def alias
9
+ @alias ||= Relation.next_alias
10
+ end
11
+
12
+ # GROUP
13
+ #
14
+ # x.group(:a) # => GROUP x By a
15
+ # x.group(:a, :b, :c) # => GROUP x BY (a, b, c)
16
+ # x.group([:a, :b, :c], :parallel => 3) # => GROUP x BY (a, b, c) PARALLEL 3
17
+ def group(*args)
18
+ grouping, options = split_at_options(args)
19
+ Group.new(self, [grouping].flatten, options)
20
+ end
21
+
22
+ # DISTINCT
23
+ #
24
+ # x.distinct # => DISTINCT x
25
+ # x.distinct(:parallel => 5) # => DISTINCT x PARALLEL 5
26
+ def distinct(options={})
27
+ Distinct.new(self, options)
28
+ end
29
+
30
+ # COGROUP
31
+ #
32
+ # x.cogroup(x => :a, y => :b) # => COGROUP x BY a, y BY b
33
+ # x.cogroup(x => :a, y => :b, z => :c) # => COGROUP x BY a, y BY b, z BY c
34
+ # x.cogroup(x => [:a, :b], y => [:c, :d]) # => COGROUP x BY (a, b), y BY (c, d)
35
+ # x.cogroup(x => :a, y => [:b, :inner]) # => COGROUP x BY a, y BY b INNER
36
+ # x.cogroup(x => :a, y => :b, :parallel => 5) # => COGROUP x BY a, y BY b PARALLEL 5
37
+ def cogroup(description)
38
+ Cogroup.new(self, description)
39
+ end
40
+
41
+ # CROSS
42
+ #
43
+ # x.cross(y) # => CROSS x, y
44
+ # x.cross(y, z, w) # => CROSS x, y, z, w
45
+ # x.cross([y, z], :parallel => 5) # => CROSS x, y, z, w PARALLEL 5
46
+ def cross(*args)
47
+ relations, options = split_at_options(args)
48
+ Cross.new(([self] + relations).flatten, options)
49
+ end
50
+
51
+ # FILTER
52
+ #
53
+ # x.filter { |r| r.a == r.b } # => FILTER x BY a == b
54
+ # x.filter { |r| r.a > r.b && r.c != 3 } # => FILTER x BY a > b AND c != 3
55
+ def filter
56
+ Filter.new(self, yield(self))
57
+ end
58
+
59
+ # FOREACH ... GENERATE
60
+ #
61
+ # x.foreach { |r| r.a } # => FOREACH x GENERATE a
62
+ # x.foreach { |r| [r.a, r.b] } # => FOREACH x GENERATE a, b
63
+ # x.foreach { |r| r.a.max } # => FOREACH x GENERATE MAX(a)
64
+ # x.foreach { |r| r.a.avg.as(:b) } # => FOREACH x GENERATE AVG(a) AS b
65
+ #
66
+ #--
67
+ #
68
+ # TODO: FOREACH a { b GENERATE c }
69
+ def foreach
70
+ Foreach.new(self, yield(self))
71
+ end
72
+
73
+ # JOIN
74
+ #
75
+ # x.join(x => :a, y => :b) # => JOIN x BY a, y BY b
76
+ # x.join(x => :a, y => :b, z => :c) # => JOIN x BY a, y BY b, z BY c
77
+ # x.join(x => :a, y => :b, :using => :replicated) # => JOIN x BY a, y BY b USING "replicated"
78
+ # x.join(x => :a, y => :b, :parallel => 5) # => JOIN x BY a, y BY b PARALLEL 5
79
+ def join(description)
80
+ Join.new(self, description)
81
+ end
82
+
83
+ # LIMIT
84
+ #
85
+ # x.limit(10) # => LIMIT x 10
86
+ def limit(n)
87
+ Limit.new(self, n)
88
+ end
89
+
90
+ # ORDER
91
+ #
92
+ # x.order(:a) # => ORDER x BY a
93
+ # x.order(:a, :b) # => ORDER x BY a, b
94
+ # x.order([:a, :asc], [:b, :desc]) # => ORDER x BY a ASC, b DESC
95
+ # x.order(:a, :parallel => 5) # => ORDER x BY a PARALLEL 5
96
+ #
97
+ #--
98
+ #
99
+ # NOTE: the syntax x.order(:a => :asc, :b => :desc) would be nice, but in
100
+ # Ruby 1.8 the order of the keys cannot be guaranteed.
101
+ def order(*args)
102
+ fields, options = split_at_options(args)
103
+ fields = *fields
104
+ Order.new(self, fields, options)
105
+ end
106
+
107
+ # SAMPLE
108
+ #
109
+ # x.sample(5) # => SAMPLE x 5;
110
+ def sample(n)
111
+ Sample.new(self, n)
112
+ end
113
+
114
+ # SPLIT
115
+ #
116
+ # y, z = x.split { |r| [r.a <= 3, r.b > 4]} # => SPLIT x INTO y IF a <= 3, z IF a > 4
117
+ def split
118
+ Split.new(self, yield(self)).shards
119
+ end
120
+
121
+ # STREAM
122
+ #
123
+ # x.stream(x, 'cut -f 3') # => STREAM x THROUGH `cut -f 3`
124
+ # x.stream([x, y], 'cut -f 3') # => STREAM x, y THROUGH `cut -f 3`
125
+ # x.stream(x, 'cut -f 3', :schema => [%w(a int)]) # => STREAM x THROUGH `cut -f 3` AS (a:int)
126
+ #
127
+ #--
128
+ #
129
+ # TODO: how to handle DEFINE'd commands?
130
+ def stream(relations, command, options={})
131
+ raise NotSupportedError
132
+ end
133
+
134
+ # UNION
135
+ #
136
+ # x.union(y) # => UNION x, y
137
+ # x.union(y, z) # => UNION x, y, z
138
+ def union(*relations)
139
+ Union.new(*([self] + relations))
140
+ end
141
+
142
+ def method_missing(name, *args)
143
+ if name.to_s =~ /^\w+$/ && args.empty?
144
+ Field::Reference.new(name, self)
145
+ else
146
+ super
147
+ end
148
+ end
149
+
150
+ def [](n)
151
+ Field::Reference.new("\$#{n}", self)
152
+ end
153
+
154
+ def hash
155
+ self.alias.hash
156
+ end
157
+
158
+ def eql?(other)
159
+ other.is_a?(Relation) && other.alias == self.alias
160
+ end
161
+
162
+ private
163
+
164
+ def split_at_options(parameters)
165
+ if parameters.last.is_a? Hash
166
+ [parameters[0..-2], parameters.last]
167
+ else
168
+ [parameters, nil]
169
+ end
170
+ end
171
+
172
+ def self.next_alias
173
+ @counter ||= 0
174
+ @counter += 1
175
+ "relation_#{@counter}"
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,15 @@
1
+ module Piglet
2
+ module Relation
3
+ class Sample # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(relation, n)
7
+ @sources, @n = [relation], n
8
+ end
9
+
10
+ def to_s
11
+ "SAMPLE #{@sources.first.alias} #{@n}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ module Piglet
2
+ module Relation
3
+ class Split # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(relation, expressions)
7
+ @sources, @expressions = [relation], expressions
8
+ @shard_map = create_shards
9
+ end
10
+
11
+ def shards
12
+ @shard_map.values_at(*@expressions)
13
+ end
14
+
15
+ def to_s
16
+ split_strings = @expressions.map do |expression|
17
+ "#{@shard_map[expression].alias} IF #{expression}"
18
+ end
19
+
20
+ "SPLIT #{@sources.first.alias} INTO #{split_strings.join(', ')}"
21
+ end
22
+
23
+ private
24
+
25
+ def create_shards
26
+ @expressions.inject({}) do |map, expr|
27
+ map[expr] = RelationShard.new(self)
28
+ map
29
+ end
30
+ end
31
+ end
32
+
33
+ class RelationShard # :nodoc:
34
+ include Relation
35
+
36
+ def initialize(split)
37
+ @sources = [split]
38
+ end
39
+
40
+ def to_s
41
+ self.alias
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Piglet
2
+ module Relation
3
+ class Stream # :nodoc:
4
+ include Relation
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ module Piglet
2
+ module Relation
3
+ class Union # :nodoc:
4
+ include Relation
5
+
6
+ def initialize(*relations)
7
+ @sources = relations
8
+ end
9
+
10
+ def to_s
11
+ "UNION #{source_aliases.join(', ')}"
12
+ end
13
+
14
+ private
15
+
16
+ def source_aliases
17
+ @sources.map { |s| s.alias }
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/piglet.rb CHANGED
@@ -1,45 +1,47 @@
1
1
  # :main: README.rdoc
2
2
  module Piglet # :nodoc:
3
- VERSION = '0.1.1'
3
+ VERSION = '0.1.2'
4
4
 
5
- autoload_files = %w(
6
- assignment
7
- cogroup
8
- cross
9
- describe
10
- distinct
11
- dump
12
- explain
13
- field
14
- field_expression_functions
15
- field_function_expression
16
- field_infix_expression
17
- field_prefix_expression
18
- field_rename
19
- field_suffix_expression
20
- filter
21
- foreach
22
- group
23
- illustrate
24
- interpreter
25
- join
26
- limit
27
- load
28
- load_and_store
29
- order
30
- relation
31
- sample
32
- split
33
- store
34
- storing
35
- stream
36
- union
37
- )
5
+ autoload :Interpreter, 'piglet/interpreter'
38
6
 
39
- autoload_files.each do |f|
40
- c = f.split('_').map { |s| s.capitalize }.join.to_sym
41
- p = "piglet/#{f}"
42
- autoload c, p
7
+ module Inout
8
+ autoload :Describe, 'piglet/inout/describe'
9
+ autoload :Dump, 'piglet/inout/dump'
10
+ autoload :Explain, 'piglet/inout/explain'
11
+ autoload :Illustrate, 'piglet/inout/illustrate'
12
+ autoload :Load, 'piglet/inout/load'
13
+ autoload :Output, 'piglet/inout/output'
14
+ autoload :StorageTypes, 'piglet/inout/storage_types'
15
+ autoload :Store, 'piglet/inout/store'
16
+ end
17
+
18
+ module Relation
19
+ autoload :Cogroup, 'piglet/relation/cogroup'
20
+ autoload :Cross, 'piglet/relation/cross'
21
+ autoload :Distinct, 'piglet/relation/distinct'
22
+ autoload :Filter, 'piglet/relation/filter'
23
+ autoload :Foreach, 'piglet/relation/foreach'
24
+ autoload :Group, 'piglet/relation/group'
25
+ autoload :Join, 'piglet/relation/join'
26
+ autoload :Limit, 'piglet/relation/limit'
27
+ autoload :Order, 'piglet/relation/order'
28
+ autoload :Relation, 'piglet/relation/relation'
29
+ autoload :Sample, 'piglet/relation/sample'
30
+ autoload :Split, 'piglet/relation/split'
31
+ autoload :Stream, 'piglet/relation/stream'
32
+ autoload :Union, 'piglet/relation/union'
33
+ end
34
+
35
+ module Field
36
+ autoload :BinaryConditional, 'piglet/field/binary_conditional'
37
+ autoload :CallExpression, 'piglet/field/call_expression'
38
+ autoload :InfixExpression, 'piglet/field/infix_expression'
39
+ autoload :Literal, 'piglet/field/literal'
40
+ autoload :Operators, 'piglet/field/operators'
41
+ autoload :PrefixExpression, 'piglet/field/prefix_expression'
42
+ autoload :Reference, 'piglet/field/reference'
43
+ autoload :Rename, 'piglet/field/rename'
44
+ autoload :SuffixExpression, 'piglet/field/suffix_expression'
43
45
  end
44
46
 
45
47
  class NotSupportedError < StandardError; end
@@ -1,10 +1,10 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
 
4
- describe Piglet::Field do
4
+ describe Piglet::Field::Reference do
5
5
 
6
6
  before do
7
- @field = Piglet::Field.new('field')
7
+ @field = Piglet::Field::Reference.new('field')
8
8
  end
9
9
 
10
10
  describe '#to_s' do
@@ -13,7 +13,7 @@ describe Piglet::Field do
13
13
  end
14
14
 
15
15
  it 'returns a string with the field name (as a symbol)' do
16
- @field = Piglet::Field.new(:field)
16
+ @field = Piglet::Field::Reference.new(:field)
17
17
  @field.to_s.should eql("field")
18
18
  end
19
19
  end
@@ -52,8 +52,8 @@ describe Piglet::Field do
52
52
 
53
53
  context 'infix and unary operators' do
54
54
  before do
55
- @field1 = Piglet::Field.new('field1')
56
- @field2 = Piglet::Field.new('field2')
55
+ @field1 = Piglet::Field::Reference.new('field1')
56
+ @field2 = Piglet::Field::Reference.new('field2')
57
57
  end
58
58
 
59
59
  [:==, :>, :<, :>=, :<=, :%, :+, :-, :*, :/].each do |op|
@@ -125,6 +125,22 @@ describe Piglet::Field do
125
125
  it 'supports casts on an expression' do
126
126
  (@field1 + @field2).cast(:chararray).to_s.should eql("(chararray) (field1 + field2)")
127
127
  end
128
+
129
+ it 'supports AND though #and on fields' do
130
+ @field1.and(@field2).to_s.should eql("field1 AND field2")
131
+ end
132
+
133
+ it 'supports AND through #and on expressions' do
134
+ (@field1 + @field2).and(@field1 - @field2).to_s.should eql("(field1 + field2) AND (field1 - field2)")
135
+ end
136
+
137
+ it 'supports OR though #or on fields' do
138
+ @field1.or(@field2).to_s.should eql("field1 OR field2")
139
+ end
140
+
141
+ it 'supports OR through #or on expressions' do
142
+ (@field1 + @field2).or(@field1 - @field2).to_s.should eql("(field1 + field2) OR (field1 - field2)")
143
+ end
128
144
  end
129
145
 
130
146
  end
@@ -40,7 +40,7 @@ describe Piglet::Interpreter do
40
40
  @interpreter.to_pig_latin.should include("LOAD 'some/path' USING XYZ;")
41
41
  end
42
42
 
43
- Piglet::LoadAndStore::LOAD_STORE_FUNCTIONS.each do |symbolic_name, function|
43
+ Piglet::Inout::StorageTypes::LOAD_STORE_FUNCTIONS.each do |symbolic_name, function|
44
44
  it "knows that the load method :#{symbolic_name} means #{function}" do
45
45
  @interpreter.interpret { store(load('some/path', :using => symbolic_name), 'out') }
46
46
  @interpreter.to_pig_latin.should include("LOAD 'some/path' USING #{function};")
@@ -267,10 +267,10 @@ describe Piglet::Interpreter do
267
267
  @interpreter.to_pig_latin.should match(/FILTER \w+ BY a == 3/)
268
268
  end
269
269
 
270
- # it 'outputs a FILTER statement with a complex test' do
271
- # @interpreter.interpret { dump(load('in').filter { |r| r.a > r.b && r.c != 3 }) }
272
- # @interpreter.to_pig_latin.should match(/FILTER \w+ BY a > b AND c != 3/)
273
- # end
270
+ it 'outputs a FILTER statement with a complex test' do
271
+ @interpreter.interpret { dump(load('in').filter { |r| (r.a > r.b).and(r.c.ne(3)) }) }
272
+ @interpreter.to_pig_latin.should match(/FILTER \w+ BY \(a > b\) AND \(c != 3\)/)
273
+ end
274
274
  end
275
275
 
276
276
  describe 'SPLIT' do
@@ -410,4 +410,50 @@ describe Piglet::Interpreter do
410
410
  end
411
411
  end
412
412
 
413
+ context 'misc. operators' do
414
+ it 'outputs a binary conditional when using #test' do
415
+ @interpreter.interpret do
416
+ dump(load('in').foreach { |r| [test(r.a == r.b, r.a, r.b)]})
417
+ end
418
+ @interpreter.to_pig_latin.should include('(a == b ? a : b)')
419
+ end
420
+ end
421
+
422
+ context 'literals' do
423
+ it 'outputs a literal string when passing a string to #literal' do
424
+ @interpreter.interpret do
425
+ dump(load('in').foreach { |r| [literal('hello').as(:world)]})
426
+ end
427
+ @interpreter.to_pig_latin.should include("'hello' AS world")
428
+ end
429
+
430
+ it 'outputs a literal integer when passing an integer to #literal' do
431
+ @interpreter.interpret do
432
+ dump(load('in').foreach { |r| [literal(3).as(:n)]})
433
+ end
434
+ @interpreter.to_pig_latin.should include("3 AS n")
435
+ end
436
+
437
+ it 'outputs a literal float when passing a float to #literal' do
438
+ @interpreter.interpret do
439
+ dump(load('in').foreach { |r| [literal(3.14).as(:pi)]})
440
+ end
441
+ @interpreter.to_pig_latin.should include("3.14 AS pi")
442
+ end
443
+
444
+ it 'outputs a literal string when passing an arbitrary object to #literal' do
445
+ @interpreter.interpret do
446
+ dump(load('in').foreach { |r| [literal(self).as(:interpreter)]})
447
+ end
448
+ @interpreter.to_pig_latin.should match(/'[^']+' AS interpreter/)
449
+ end
450
+
451
+ it 'escapes single quotes in literal strings' do
452
+ @interpreter.interpret do
453
+ dump(load('in').foreach { |r| [literal("hello 'world'").as(:str)]})
454
+ end
455
+ @interpreter.to_pig_latin.should include("'hello \\'world\\'' AS str")
456
+ end
457
+ end
458
+
413
459
  end
@@ -1,11 +1,11 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
 
4
- describe Piglet::Relation do
4
+ describe Piglet::Relation::Relation do
5
5
 
6
6
  before do
7
7
  @relation = Object.new
8
- @relation.extend Piglet::Relation
8
+ @relation.extend Piglet::Relation::Relation
9
9
  end
10
10
 
11
11
  it 'has a alias' do
@@ -16,7 +16,7 @@ describe Piglet::Relation do
16
16
  aliases = { }
17
17
  1000.times do
18
18
  @relation = Object.new
19
- @relation.extend Piglet::Relation
19
+ @relation.extend Piglet::Relation::Relation
20
20
  aliases.should_not have_key(@relation.alias)
21
21
  aliases[@relation.alias] = @relation
22
22
  end
@@ -37,7 +37,7 @@ describe Piglet::Relation do
37
37
  describe '#cross' do
38
38
  it 'returns a new relation with the target relation as one of the sources' do
39
39
  other = Object.new
40
- other.extend Piglet::Relation
40
+ other.extend Piglet::Relation::Relation
41
41
  @relation.cross(other).sources.should include(@relation)
42
42
  end
43
43
  end
@@ -45,7 +45,7 @@ describe Piglet::Relation do
45
45
  describe '#union' do
46
46
  it 'returns a new relation with the target relation as one of the sources' do
47
47
  other = Object.new
48
- other.extend Piglet::Relation
48
+ other.extend Piglet::Relation::Relation
49
49
  @relation.union(other).sources.should include(@relation)
50
50
  end
51
51
  end
@@ -1,27 +1,27 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
 
4
- describe Piglet::Split do
4
+ describe Piglet::Relation::Split do
5
5
 
6
6
  before do
7
7
  @relation = mock('source')
8
8
  @expr1 = mock('expr1')
9
9
  @expr2 = mock('expr2')
10
10
  @relation.stub!(:alias).and_return('rel')
11
- @expr1.stub!(:to_s).and_return('y')
12
- @expr2.stub!(:to_s).and_return('w')
13
- @split = Piglet::Split.new(@relation, [@expr1, @expr2])
11
+ @expr1.stub!(:to_s).and_return('expr1')
12
+ @expr2.stub!(:to_s).and_return('expr2')
13
+ @split = Piglet::Relation::Split.new(@relation, [@expr1, @expr2])
14
14
  end
15
15
 
16
16
  describe '#to_s' do
17
17
  it 'outputs all x IF y expressions' do
18
- @split.to_s.should match(/SPLIT rel INTO \w+ IF [yw], \w+ IF [yw]/)
18
+ @split.to_s.should match(/SPLIT rel INTO \w+ IF expr[12], \w+ IF expr[12]/)
19
19
  end
20
20
 
21
21
  it 'contains the names of all the shard relations' do
22
22
  @shards = @split.shards
23
- @split.to_s.should include("#{@shards[0].alias} IF y")
24
- @split.to_s.should include("#{@shards[1].alias} IF w")
23
+ @split.to_s.should include("#{@shards[0].alias} IF expr1")
24
+ @split.to_s.should include("#{@shards[1].alias} IF expr2")
25
25
  end
26
26
  end
27
27
 
data/spec/spec_helper.rb CHANGED
@@ -7,8 +7,6 @@ require 'spec'
7
7
  require 'spec/autorun'
8
8
 
9
9
 
10
- require 'piglet/interpreter'
11
-
12
10
  Spec::Runner.configure do |config|
13
11
 
14
12
  end