alf 0.9.0 → 0.9.1
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.
- data/CHANGELOG.md +64 -0
- data/Gemfile.lock +4 -4
- data/README.md +257 -171
- data/TODO.md +4 -4
- data/alf.gemspec +3 -3
- data/alf.noespec +11 -6
- data/examples/pseudo-with.alf +7 -0
- data/examples/runall.sh +2 -2
- data/examples/unwrap.alf +4 -0
- data/examples/wrap.alf +2 -0
- data/lib/alf/relation.rb +118 -0
- data/lib/alf/version.rb +1 -1
- data/lib/alf.rb +320 -169
- data/spec/integration/src/test_minus.alf +5 -0
- data/spec/integration/src/test_project.alf +9 -0
- data/spec/{alf_spec.rb → integration/test_alf.rb} +8 -21
- data/spec/integration/test_alf_specs.rb +37 -0
- data/spec/{examples_spec.rb → integration/test_examples.rb} +1 -1
- data/spec/spec_helper.rb +19 -1
- data/spec/unit/environment/examples/suppliers.rash +5 -0
- data/spec/{environment/explicit_spec.rb → unit/environment/test_explicit.rb} +0 -0
- data/spec/{environment/folder_spec.rb → unit/environment/test_folder.rb} +1 -1
- data/spec/{operator → unit/operator}/non_relational/compact/buffer_based.rb +0 -0
- data/spec/{operator/non_relational/compact/sort_based_spec.rb → unit/operator/non_relational/compact/test_sort_based.rb} +0 -0
- data/spec/{operator/non_relational/autonum_spec.rb → unit/operator/non_relational/test_autonum.rb} +0 -0
- data/spec/{operator/non_relational/clip_spec.rb → unit/operator/non_relational/test_clip.rb} +0 -0
- data/spec/{operator/non_relational/compact_spec.rb → unit/operator/non_relational/test_compact.rb} +0 -0
- data/spec/{operator/non_relational/defaults_spec.rb → unit/operator/non_relational/test_defaults.rb} +0 -0
- data/spec/{operator/non_relational/sort_spec.rb → unit/operator/non_relational/test_sort.rb} +0 -0
- data/spec/{operator/relational/join/hash_based_spec.rb → unit/operator/relational/join/test_hash_based.rb} +0 -0
- data/spec/unit/operator/relational/summarize/test_hash_based.rb +38 -0
- data/spec/{operator/relational/summarize/sort_based_spec.rb → unit/operator/relational/summarize/test_sort_based.rb} +0 -0
- data/spec/{operator/relational/extend_spec.rb → unit/operator/relational/test_extend.rb} +0 -0
- data/spec/{operator/relational/group_spec.rb → unit/operator/relational/test_group.rb} +3 -2
- data/spec/{operator/relational/intersect_spec.rb → unit/operator/relational/test_intersect.rb} +0 -0
- data/spec/unit/operator/relational/test_join.rb +36 -0
- data/spec/{operator/relational/minus_spec.rb → unit/operator/relational/test_minus.rb} +0 -0
- data/spec/{operator/relational/project_spec.rb → unit/operator/relational/test_project.rb} +0 -0
- data/spec/{operator/relational/quota_spec.rb → unit/operator/relational/test_quota.rb} +0 -0
- data/spec/{operator/relational/rename_spec.rb → unit/operator/relational/test_rename.rb} +0 -0
- data/spec/{operator/relational/restrict_spec.rb → unit/operator/relational/test_restrict.rb} +0 -0
- data/spec/unit/operator/relational/test_summarize.rb +64 -0
- data/spec/{operator/relational/ungroup_spec.rb → unit/operator/relational/test_ungroup.rb} +0 -0
- data/spec/{operator/relational/union_spec.rb → unit/operator/relational/test_union.rb} +0 -0
- data/spec/{operator/relational/unnest_spec.rb → unit/operator/relational/test_unwrap.rb} +5 -5
- data/spec/{operator/relational/nest_spec.rb → unit/operator/relational/test_wrap.rb} +5 -5
- data/spec/{operator/command_methods_spec.rb → unit/operator/test_command_methods.rb} +0 -0
- data/spec/unit/operator/test_non_relational.rb +18 -0
- data/spec/unit/operator/test_relational.rb +27 -0
- data/spec/{reader → unit/reader}/input.rb +0 -0
- data/spec/unit/reader/test_alf_file.rb +27 -0
- data/spec/{reader/rash_spec.rb → unit/reader/test_rash.rb} +0 -0
- data/spec/unit/relation/test_coerce.rb +53 -0
- data/spec/unit/relation/test_inspect.rb +20 -0
- data/spec/unit/relation/test_relops.rb +46 -0
- data/spec/{renderer/text/cell_spec.rb → unit/renderer/text/test_cell.rb} +0 -0
- data/spec/{renderer/text/row_spec.rb → unit/renderer/text/test_row.rb} +0 -0
- data/spec/{renderer/text/table_spec.rb → unit/renderer/text/test_table.rb} +0 -0
- data/spec/{aggregator_spec.rb → unit/test_aggregator.rb} +6 -6
- data/spec/{assumptions_spec.rb → unit/test_assumptions.rb} +0 -0
- data/spec/{lispy_spec.rb → unit/test_lispy.rb} +0 -0
- data/spec/unit/test_operator.rb +16 -0
- data/spec/{reader_spec.rb → unit/test_reader.rb} +4 -0
- data/spec/unit/test_relation.rb +40 -0
- data/spec/{renderer_spec.rb → unit/test_renderer.rb} +0 -0
- data/spec/{tools/ordering_key_spec.rb → unit/tools/test_ordering_key.rb} +0 -0
- data/spec/{tools/projection_key_spec.rb → unit/tools/test_projection_key.rb} +0 -0
- data/spec/{tools/tools_spec.rb → unit/tools/test_tools.rb} +0 -0
- data/spec/{tools/tuple_handle_spec.rb → unit/tools/test_tuple_handle.rb} +0 -0
- data/tasks/clean.rake +3 -0
- data/tasks/spec_test.rake +1 -1
- metadata +143 -114
- data/examples/nest.alf +0 -2
- data/examples/unnest.alf +0 -4
- data/examples/with.alf +0 -23
- data/spec/operator/relational/summarize_spec.rb +0 -41
- data/spec/reader/alf_file_spec.rb +0 -15
|
@@ -18,30 +18,17 @@ describe Alf do
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
it "should allow compiling lispy expressions" do
|
|
21
|
-
lispy.compile{
|
|
21
|
+
lispy.compile {
|
|
22
22
|
(restrict :suppliers, lambda{ city == 'London'})
|
|
23
23
|
}.to_a.should == expected
|
|
24
24
|
end
|
|
25
|
-
|
|
26
|
-
it "should allow defining temporary expressions" do
|
|
27
|
-
lispy.compile{
|
|
28
|
-
with(:sup => (dataset :suppliers)) do
|
|
29
|
-
(restrict :sup, lambda{ city == 'London'})
|
|
30
|
-
end
|
|
31
|
-
}.to_a.should == expected
|
|
32
|
-
end
|
|
33
25
|
|
|
34
|
-
it "should allow
|
|
35
|
-
|
|
36
|
-
(restrict :suppliers, lambda{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
end
|
|
41
|
-
projection.to_a.should == [
|
|
42
|
-
{:city => 'Paris'},
|
|
43
|
-
{:city => 'Athens'}
|
|
44
|
-
]
|
|
26
|
+
it "should allow evaluating lispy expressions" do
|
|
27
|
+
rel = lispy.evaluate {
|
|
28
|
+
(restrict :suppliers, lambda{ city == 'London'})
|
|
29
|
+
}
|
|
30
|
+
rel.should be_a(Alf::Relation)
|
|
31
|
+
rel.should eq(Alf::Relation.coerce(expected))
|
|
45
32
|
end
|
|
46
|
-
|
|
33
|
+
|
|
47
34
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
describe "Alf's integration tests" do
|
|
3
|
+
|
|
4
|
+
module Helpers
|
|
5
|
+
|
|
6
|
+
def rel_equal(x, y)
|
|
7
|
+
x.to_rel == y.to_rel
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def specify(message, x)
|
|
11
|
+
raise message unless x
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
shared_examples_for "An integration file" do
|
|
17
|
+
|
|
18
|
+
let(:lispy){
|
|
19
|
+
lispy = Alf.lispy(Alf::Environment.examples)
|
|
20
|
+
lispy.ruby_extend(Helpers)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
it "should work when executed with a Alf" do
|
|
24
|
+
lispy.compile(File.read(subject))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end # An example
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Dir["#{File.expand_path('../src', __FILE__)}/**/*.alf"].each do |file|
|
|
31
|
+
describe file do
|
|
32
|
+
subject{ file }
|
|
33
|
+
it_should_behave_like "An integration file"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -15,7 +15,7 @@ module Alf
|
|
|
15
15
|
end # An example
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
Dir["#{File.expand_path('
|
|
18
|
+
Dir["#{File.expand_path('../../../examples', __FILE__)}/**/*.alf"].each do |file|
|
|
19
19
|
describe file do
|
|
20
20
|
subject{ file }
|
|
21
21
|
it_should_behave_like "An example"
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path('
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
|
2
2
|
require 'alf'
|
|
3
3
|
|
|
4
4
|
Alf::Lispy.extend(Alf::Lispy)
|
|
5
5
|
|
|
6
|
+
def rel(*args)
|
|
7
|
+
Alf::Relation.coerce(args)
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
shared_examples_for "An operator class" do
|
|
7
11
|
|
|
8
12
|
it "should not have public set_args, _each and _prepare methods" do
|
|
@@ -22,5 +26,19 @@ shared_examples_for "An operator class" do
|
|
|
22
26
|
it "should have a public each method" do
|
|
23
27
|
operator_class.public_method_defined?(:each).should be_true
|
|
24
28
|
end
|
|
29
|
+
|
|
30
|
+
it "should have a unary? class method" do
|
|
31
|
+
operator_class.should respond_to(:unary?)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should have a binary? class method" do
|
|
35
|
+
operator_class.should respond_to(:binary?)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should implement unary? and binary? accurately" do
|
|
39
|
+
operator_class.unary?.should_not eq(operator_class.binary?)
|
|
40
|
+
operator_class.unary?.should eq(operator_class.ancestors.include?(Alf::Operator::Unary))
|
|
41
|
+
operator_class.binary?.should eq(operator_class.ancestors.include?(Alf::Operator::Binary))
|
|
42
|
+
end
|
|
25
43
|
|
|
26
44
|
end
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'}
|
|
2
|
+
{:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'}
|
|
3
|
+
{:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'}
|
|
4
|
+
{:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'}
|
|
5
|
+
{:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/spec/{operator/non_relational/autonum_spec.rb → unit/operator/non_relational/test_autonum.rb}
RENAMED
|
File without changes
|
data/spec/{operator/non_relational/clip_spec.rb → unit/operator/non_relational/test_clip.rb}
RENAMED
|
File without changes
|
data/spec/{operator/non_relational/compact_spec.rb → unit/operator/non_relational/test_compact.rb}
RENAMED
|
File without changes
|
data/spec/{operator/non_relational/defaults_spec.rb → unit/operator/non_relational/test_defaults.rb}
RENAMED
|
File without changes
|
data/spec/{operator/non_relational/sort_spec.rb → unit/operator/non_relational/test_sort.rb}
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
module Operator::Relational
|
|
4
|
+
describe Summarize::HashBased do
|
|
5
|
+
|
|
6
|
+
let(:input) {[
|
|
7
|
+
{:a => "via_method", :time => 1},
|
|
8
|
+
{:a => "via_reader", :time => 4},
|
|
9
|
+
{:a => "via_method", :time => 2},
|
|
10
|
+
{:a => "via_reader", :time => 2},
|
|
11
|
+
{:a => "via_method", :time => 1},
|
|
12
|
+
]}
|
|
13
|
+
|
|
14
|
+
let(:expected) {[
|
|
15
|
+
{:a => "via_method", :time_sum => 4, :time_max => 2},
|
|
16
|
+
{:a => "via_reader", :time_sum => 6, :time_max => 4},
|
|
17
|
+
]}
|
|
18
|
+
|
|
19
|
+
let(:aggs){{:time_sum => Aggregator.sum(:time),
|
|
20
|
+
:time_max => Aggregator.max(:time)}}
|
|
21
|
+
let(:operator){ Summarize::HashBased.new(by_key, aggs) }
|
|
22
|
+
|
|
23
|
+
before{ operator.pipe(input) }
|
|
24
|
+
subject{ operator.to_a.sort{|t1,t2| t1[:a] <=> t2[:a]} }
|
|
25
|
+
|
|
26
|
+
describe "when allbut is not set" do
|
|
27
|
+
let(:by_key){ Tools::ProjectionKey.new([:a], false) }
|
|
28
|
+
it { should == expected }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "when allbut is set" do
|
|
32
|
+
let(:by_key){ Tools::ProjectionKey.new([:time], true) }
|
|
33
|
+
it { should == expected }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -13,8 +13,9 @@ module Alf
|
|
|
13
13
|
]}
|
|
14
14
|
|
|
15
15
|
let(:expected) {[
|
|
16
|
-
{:a => "via_method", :as =>
|
|
17
|
-
|
|
16
|
+
{:a => "via_method", :as => rel({:time => 1, :b => "b"},
|
|
17
|
+
{:time => 2, :b => "b"})},
|
|
18
|
+
{:a => "via_reader", :as => rel({:time => 3, :b => "b"})},
|
|
18
19
|
]}
|
|
19
20
|
|
|
20
21
|
subject{ operator.to_a.sort{|k1,k2| k1[:a] <=> k2[:a]} }
|
data/spec/{operator/relational/intersect_spec.rb → unit/operator/relational/test_intersect.rb}
RENAMED
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
module Operator::Relational
|
|
4
|
+
describe Join do
|
|
5
|
+
|
|
6
|
+
let(:suppliers){Relation.coerce [
|
|
7
|
+
{:sid => 'S1', :city => 'London'},
|
|
8
|
+
{:sid => 'S2', :city => 'Paris'},
|
|
9
|
+
{:sid => 'S3', :city => 'Paris'},
|
|
10
|
+
{:sid => 'S4', :city => 'London'},
|
|
11
|
+
{:sid => 'S5', :city => 'Athens'},
|
|
12
|
+
]}
|
|
13
|
+
|
|
14
|
+
describe "when applied to sub-relations" do
|
|
15
|
+
let(:suppliers_by_city){Relation.coerce(
|
|
16
|
+
Lispy.group(suppliers, [:sid], :suppliers)
|
|
17
|
+
)}
|
|
18
|
+
let(:s2_s3){Relation.coerce([
|
|
19
|
+
{:sid => 'S3'},
|
|
20
|
+
{:sid => 'S2'}
|
|
21
|
+
])}
|
|
22
|
+
let(:right){Relation.coerce([
|
|
23
|
+
{:suppliers => s2_s3, :hello => "world"}
|
|
24
|
+
])}
|
|
25
|
+
let(:expected){Relation.coerce([
|
|
26
|
+
{:suppliers => s2_s3, :hello => "world", :city => 'Paris'}
|
|
27
|
+
])}
|
|
28
|
+
subject{Relation.coerce(
|
|
29
|
+
Lispy.join(suppliers_by_city, right)
|
|
30
|
+
)}
|
|
31
|
+
it{ should == expected }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/spec/{operator/relational/restrict_spec.rb → unit/operator/relational/test_restrict.rb}
RENAMED
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
module Operator::Relational
|
|
4
|
+
describe Summarize do
|
|
5
|
+
|
|
6
|
+
let(:operator_class){ Summarize }
|
|
7
|
+
it_should_behave_like("An operator class")
|
|
8
|
+
|
|
9
|
+
let(:input) {[
|
|
10
|
+
{:a => "via_reader", :time => 2},
|
|
11
|
+
{:a => "via_method", :time => 1},
|
|
12
|
+
{:a => "via_method", :time => 2},
|
|
13
|
+
{:a => "via_reader", :time => 4},
|
|
14
|
+
{:a => "via_method", :time => 1},
|
|
15
|
+
]}
|
|
16
|
+
|
|
17
|
+
let(:expected) {[
|
|
18
|
+
{:a => "via_method", :time_sum => 4, :time_max => 2, :time_avg => 4.0/3},
|
|
19
|
+
{:a => "via_reader", :time_sum => 6, :time_max => 4, :time_avg => 6.0/2},
|
|
20
|
+
]}
|
|
21
|
+
|
|
22
|
+
let(:aggs){{:time_sum => Aggregator.sum(:time),
|
|
23
|
+
:time_max => Aggregator.max(:time),
|
|
24
|
+
:time_avg => Aggregator.avg(:time)}}
|
|
25
|
+
|
|
26
|
+
subject{ operator.to_a.sort{|t1,t2| t1[:a] <=> t2[:a]} }
|
|
27
|
+
|
|
28
|
+
describe "without allbut" do
|
|
29
|
+
|
|
30
|
+
describe "When factored with commandline args" do
|
|
31
|
+
let(:opts){ ["--by=a"] }
|
|
32
|
+
let(:aggs){ ["time_sum", "sum(:time)", "time_max", "max(:time)", "time_avg", "avg(:time)"] }
|
|
33
|
+
let(:operator){ Summarize.run(opts + ["--"] +aggs) }
|
|
34
|
+
before{ operator.pipe(input) }
|
|
35
|
+
it { should == expected }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "When factored with Lispy" do
|
|
39
|
+
let(:operator){ Lispy.summarize(input, [:a], aggs) }
|
|
40
|
+
it { should == expected }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "with allbut" do
|
|
46
|
+
|
|
47
|
+
describe "When factored with commandline args" do
|
|
48
|
+
let(:opts){ ["--by=time", "--allbut"] }
|
|
49
|
+
let(:aggs){ ["time_sum", "sum(:time)", "time_max", "max(:time)", "time_avg", "avg(:time)"] }
|
|
50
|
+
let(:operator){ Summarize.run(opts + ["--"] + aggs) }
|
|
51
|
+
before{ operator.pipe(input) }
|
|
52
|
+
it { should == expected }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe "When factored with Lispy" do
|
|
56
|
+
let(:operator){ Lispy.summarize(input, [:time], aggs, true) }
|
|
57
|
+
it { should == expected }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
module Alf
|
|
3
3
|
module Operator::Relational
|
|
4
|
-
describe
|
|
4
|
+
describe Unwrap do
|
|
5
5
|
|
|
6
|
-
let(:operator_class){
|
|
6
|
+
let(:operator_class){ Unwrap }
|
|
7
7
|
it_should_behave_like("An operator class")
|
|
8
8
|
|
|
9
9
|
let(:input) {[
|
|
10
|
-
{:
|
|
10
|
+
{:wrapped => {:a => "a", :b => "b"}, :c => "c"}
|
|
11
11
|
]}
|
|
12
12
|
|
|
13
13
|
let(:expected) {[
|
|
@@ -17,13 +17,13 @@ module Alf
|
|
|
17
17
|
subject{ operator.to_a }
|
|
18
18
|
|
|
19
19
|
describe "when factored with commandline args" do
|
|
20
|
-
let(:operator){
|
|
20
|
+
let(:operator){ Unwrap.run(%w{-- wrapped}) }
|
|
21
21
|
before{ operator.pipe(input) }
|
|
22
22
|
it { should == expected }
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
describe "when factored with Lispy" do
|
|
26
|
-
let(:operator){ Lispy.
|
|
26
|
+
let(:operator){ Lispy.unwrap(input, :wrapped) }
|
|
27
27
|
it { should == expected }
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
module Alf
|
|
3
3
|
module Operator::Relational
|
|
4
|
-
describe
|
|
4
|
+
describe Wrap do
|
|
5
5
|
|
|
6
|
-
let(:operator_class){
|
|
6
|
+
let(:operator_class){ Wrap }
|
|
7
7
|
it_should_behave_like("An operator class")
|
|
8
8
|
|
|
9
9
|
let(:input) {[
|
|
@@ -11,19 +11,19 @@ module Alf
|
|
|
11
11
|
]}
|
|
12
12
|
|
|
13
13
|
let(:expected) {[
|
|
14
|
-
{:
|
|
14
|
+
{:wraped => {:a => "a", :b => "b"}, :c => "c"}
|
|
15
15
|
]}
|
|
16
16
|
|
|
17
17
|
subject{ operator.to_a }
|
|
18
18
|
|
|
19
19
|
describe "when factored with commandline args" do
|
|
20
|
-
let(:operator){
|
|
20
|
+
let(:operator){ Wrap.run(["--", "a", "b", "wraped"]) }
|
|
21
21
|
before{ operator.pipe(input) }
|
|
22
22
|
it { should == expected }
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
describe "when factored with Lispy" do
|
|
26
|
-
let(:operator){ Lispy.
|
|
26
|
+
let(:operator){ Lispy.wrap(input, [:a, :b], :wraped) }
|
|
27
27
|
it { should == expected }
|
|
28
28
|
end
|
|
29
29
|
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Operator::NonRelational do
|
|
4
|
+
|
|
5
|
+
specify "each" do
|
|
6
|
+
x = []
|
|
7
|
+
Operator::NonRelational.each{|m| x << m}
|
|
8
|
+
x.sort{|m1,m2| m1.name.to_s <=> m2.name.to_s}.should == [
|
|
9
|
+
Alf::Operator::NonRelational::Autonum,
|
|
10
|
+
Alf::Operator::NonRelational::Clip,
|
|
11
|
+
Alf::Operator::NonRelational::Compact,
|
|
12
|
+
Alf::Operator::NonRelational::Defaults,
|
|
13
|
+
Alf::Operator::NonRelational::Sort,
|
|
14
|
+
]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Operator::Relational do
|
|
4
|
+
|
|
5
|
+
specify "each" do
|
|
6
|
+
x = []
|
|
7
|
+
Operator::Relational.each{|m| x << m}
|
|
8
|
+
x.sort{|m1,m2| m1.name.to_s <=> m2.name.to_s}.should == [
|
|
9
|
+
Alf::Operator::Relational::Extend,
|
|
10
|
+
Alf::Operator::Relational::Group,
|
|
11
|
+
Alf::Operator::Relational::Intersect,
|
|
12
|
+
Alf::Operator::Relational::Join,
|
|
13
|
+
Alf::Operator::Relational::Minus,
|
|
14
|
+
Alf::Operator::Relational::Project,
|
|
15
|
+
Alf::Operator::Relational::Quota,
|
|
16
|
+
Alf::Operator::Relational::Rename,
|
|
17
|
+
Alf::Operator::Relational::Restrict,
|
|
18
|
+
Alf::Operator::Relational::Summarize,
|
|
19
|
+
Alf::Operator::Relational::Ungroup,
|
|
20
|
+
Alf::Operator::Relational::Union,
|
|
21
|
+
Alf::Operator::Relational::Unwrap,
|
|
22
|
+
Alf::Operator::Relational::Wrap,
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Reader::AlfFile do
|
|
4
|
+
|
|
5
|
+
let(:io){ StringIO.new(expr) }
|
|
6
|
+
def dataset(name)
|
|
7
|
+
[{:status => 10},{:status => 30}]
|
|
8
|
+
end
|
|
9
|
+
subject{ Reader::AlfFile.new(io, self).to_a }
|
|
10
|
+
|
|
11
|
+
describe "on pure functional expressions" do
|
|
12
|
+
let(:expr){ "(restrict :suppliers, lambda{status > 20})" }
|
|
13
|
+
it{ should == [{:status => 30}]}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "on impure functional expressions" do
|
|
17
|
+
let(:expr){
|
|
18
|
+
<<-EOF
|
|
19
|
+
xxx = (restrict :suppliers, lambda{status > 20})
|
|
20
|
+
(extend xxx, :rev => lambda{ -status })
|
|
21
|
+
EOF
|
|
22
|
+
}
|
|
23
|
+
it{ should == [{:status => 30, :rev => -30}]}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Relation do
|
|
4
|
+
|
|
5
|
+
let(:tuples_by_sid){[
|
|
6
|
+
{:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
|
|
7
|
+
{:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
|
|
8
|
+
{:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'}
|
|
9
|
+
]}
|
|
10
|
+
let(:rel){ Relation.new tuples_by_sid.to_set }
|
|
11
|
+
let(:tuples_by_name){ tuples_by_sid.sort{|t1,t2| t1[:name] <=> t2[:name]} }
|
|
12
|
+
|
|
13
|
+
describe "coerce" do
|
|
14
|
+
|
|
15
|
+
subject{ Relation.coerce(arg) }
|
|
16
|
+
|
|
17
|
+
describe "with a Relation" do
|
|
18
|
+
let(:arg){ rel }
|
|
19
|
+
it{ should be_a(Relation) }
|
|
20
|
+
it{ should == rel }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "with a set of tuples" do
|
|
24
|
+
let(:arg){ tuples_by_name.to_set }
|
|
25
|
+
it{ should be_a(Relation) }
|
|
26
|
+
it{ should == rel }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "with an array of tuples" do
|
|
30
|
+
let(:arg){ tuples_by_name }
|
|
31
|
+
it{ should be_a(Relation) }
|
|
32
|
+
it{ should == rel }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "with an iterator" do
|
|
36
|
+
let(:arg){ Lispy.restrict(tuples_by_name, lambda{ true }) }
|
|
37
|
+
it{ should be_a(Relation) }
|
|
38
|
+
it{ should == rel }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "with unrecognized arg" do
|
|
42
|
+
let(:arg){ nil }
|
|
43
|
+
specify{ lambda{ subject }.should raise_error(ArgumentError) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should be semi-aliased as []" do
|
|
47
|
+
Alf::Relation[*tuples_by_name].should == rel
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end # coerce
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Relation do
|
|
4
|
+
|
|
5
|
+
let(:rel){Relation.coerce([
|
|
6
|
+
{:sid => 'S1'},
|
|
7
|
+
{:sid => 'S2'},
|
|
8
|
+
{:sid => 'S3'}
|
|
9
|
+
])}
|
|
10
|
+
|
|
11
|
+
describe "inspect" do
|
|
12
|
+
|
|
13
|
+
it "should allows the litteral round-trip" do
|
|
14
|
+
Kernel.eval(rel.inspect).should == rel
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end # coerce
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
module Alf
|
|
3
|
+
describe Relation do
|
|
4
|
+
|
|
5
|
+
let(:rel1){rel(
|
|
6
|
+
{:sid => 'S1'},
|
|
7
|
+
{:sid => 'S2'},
|
|
8
|
+
{:sid => 'S3'}
|
|
9
|
+
)}
|
|
10
|
+
|
|
11
|
+
let(:rel2){rel(
|
|
12
|
+
{:sid => 'S5'},
|
|
13
|
+
{:sid => 'S2'}
|
|
14
|
+
)}
|
|
15
|
+
|
|
16
|
+
specify "extend" do
|
|
17
|
+
rel1.extend(:x => lambda{ sid.downcase }).should == rel(
|
|
18
|
+
{:sid => 'S1', :x => 's1'},
|
|
19
|
+
{:sid => 'S2', :x => 's2'},
|
|
20
|
+
{:sid => 'S3', :x => 's3'}
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
specify "union" do
|
|
25
|
+
(rel1 + rel1).should == rel1
|
|
26
|
+
(rel1 + rel2).should == rel(
|
|
27
|
+
{:sid => 'S1'},
|
|
28
|
+
{:sid => 'S3'},
|
|
29
|
+
{:sid => 'S2'},
|
|
30
|
+
{:sid => 'S5'}
|
|
31
|
+
)
|
|
32
|
+
end # coerce
|
|
33
|
+
|
|
34
|
+
specify "difference" do
|
|
35
|
+
(rel1 - rel1).should == rel()
|
|
36
|
+
(rel1 - rel2).should == rel(
|
|
37
|
+
{:sid => 'S1'},
|
|
38
|
+
{:sid => 'S3'}
|
|
39
|
+
)
|
|
40
|
+
(rel2 - rel1).should == rel(
|
|
41
|
+
{:sid => 'S5'}
|
|
42
|
+
)
|
|
43
|
+
end # coerce
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -42,16 +42,16 @@ module Alf
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it "should behave correctly on group" do
|
|
45
|
-
Aggregator.group(:a).aggregate(input).should ==
|
|
45
|
+
Aggregator.group(:a).aggregate(input).should == rel(
|
|
46
46
|
{:a => 1},
|
|
47
47
|
{:a => 2},
|
|
48
|
-
{:a => 3}
|
|
49
|
-
|
|
50
|
-
Aggregator.group(:a, :sign).aggregate(input).should ==
|
|
48
|
+
{:a => 3}
|
|
49
|
+
)
|
|
50
|
+
Aggregator.group(:a, :sign).aggregate(input).should == rel(
|
|
51
51
|
{:a => 1, :sign => -1},
|
|
52
52
|
{:a => 2, :sign => 1 },
|
|
53
|
-
{:a => 3, :sign => -1}
|
|
54
|
-
|
|
53
|
+
{:a => 3, :sign => -1}
|
|
54
|
+
)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it "should allow specific tuple computations" do
|