alf 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +42 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +769 -0
  7. data/Rakefile +23 -0
  8. data/TODO.md +26 -0
  9. data/alf.gemspec +191 -0
  10. data/alf.noespec +30 -0
  11. data/bin/alf +31 -0
  12. data/examples/autonum.alf +6 -0
  13. data/examples/cities.rash +4 -0
  14. data/examples/clip.alf +3 -0
  15. data/examples/compact.alf +2 -0
  16. data/examples/database.alf +6 -0
  17. data/examples/defaults.alf +3 -0
  18. data/examples/extend.alf +3 -0
  19. data/examples/group.alf +3 -0
  20. data/examples/intersect.alf +4 -0
  21. data/examples/join.alf +2 -0
  22. data/examples/minus.alf +8 -0
  23. data/examples/nest.alf +2 -0
  24. data/examples/nulls.rash +3 -0
  25. data/examples/parts.rash +6 -0
  26. data/examples/project.alf +2 -0
  27. data/examples/quota.alf +4 -0
  28. data/examples/rename.alf +3 -0
  29. data/examples/restrict.alf +2 -0
  30. data/examples/runall.sh +26 -0
  31. data/examples/schema.yaml +28 -0
  32. data/examples/sort.alf +4 -0
  33. data/examples/summarize.alf +16 -0
  34. data/examples/suppliers.rash +5 -0
  35. data/examples/supplies.rash +12 -0
  36. data/examples/ungroup.alf +4 -0
  37. data/examples/union.alf +3 -0
  38. data/examples/unnest.alf +4 -0
  39. data/examples/with.alf +23 -0
  40. data/lib/alf.rb +2984 -0
  41. data/lib/alf/loader.rb +1 -0
  42. data/lib/alf/renderer/text.rb +153 -0
  43. data/lib/alf/renderer/yaml.rb +22 -0
  44. data/lib/alf/version.rb +14 -0
  45. data/spec/aggregator_spec.rb +62 -0
  46. data/spec/alf_spec.rb +47 -0
  47. data/spec/assumptions_spec.rb +15 -0
  48. data/spec/environment/explicit_spec.rb +15 -0
  49. data/spec/environment/folder_spec.rb +30 -0
  50. data/spec/examples_spec.rb +26 -0
  51. data/spec/lispy_spec.rb +23 -0
  52. data/spec/operator/command_methods_spec.rb +38 -0
  53. data/spec/operator/non_relational/autonum_spec.rb +61 -0
  54. data/spec/operator/non_relational/clip_spec.rb +49 -0
  55. data/spec/operator/non_relational/compact/buffer_based.rb +30 -0
  56. data/spec/operator/non_relational/compact/sort_based_spec.rb +30 -0
  57. data/spec/operator/non_relational/compact_spec.rb +38 -0
  58. data/spec/operator/non_relational/defaults_spec.rb +55 -0
  59. data/spec/operator/non_relational/sort_spec.rb +66 -0
  60. data/spec/operator/relational/extend_spec.rb +34 -0
  61. data/spec/operator/relational/group_spec.rb +54 -0
  62. data/spec/operator/relational/intersect_spec.rb +58 -0
  63. data/spec/operator/relational/join/hash_based_spec.rb +63 -0
  64. data/spec/operator/relational/minus_spec.rb +56 -0
  65. data/spec/operator/relational/nest_spec.rb +32 -0
  66. data/spec/operator/relational/project_spec.rb +65 -0
  67. data/spec/operator/relational/quota_spec.rb +44 -0
  68. data/spec/operator/relational/rename_spec.rb +32 -0
  69. data/spec/operator/relational/restrict_spec.rb +56 -0
  70. data/spec/operator/relational/summarize/sort_based_spec.rb +31 -0
  71. data/spec/operator/relational/summarize_spec.rb +41 -0
  72. data/spec/operator/relational/ungroup_spec.rb +35 -0
  73. data/spec/operator/relational/union_spec.rb +35 -0
  74. data/spec/operator/relational/unnest_spec.rb +32 -0
  75. data/spec/reader/alf_file_spec.rb +15 -0
  76. data/spec/reader/input.rb +2 -0
  77. data/spec/reader/rash_spec.rb +31 -0
  78. data/spec/reader_spec.rb +27 -0
  79. data/spec/renderer/text/cell_spec.rb +34 -0
  80. data/spec/renderer/text/row_spec.rb +30 -0
  81. data/spec/renderer/text/table_spec.rb +39 -0
  82. data/spec/renderer_spec.rb +42 -0
  83. data/spec/spec_helper.rb +26 -0
  84. data/spec/tools/ordering_key_spec.rb +81 -0
  85. data/spec/tools/projection_key_spec.rb +83 -0
  86. data/spec/tools/tools_spec.rb +25 -0
  87. data/spec/tools/tuple_handle_spec.rb +78 -0
  88. data/tasks/debug_mail.rake +78 -0
  89. data/tasks/debug_mail.txt +13 -0
  90. data/tasks/gem.rake +68 -0
  91. data/tasks/spec_test.rake +79 -0
  92. data/tasks/unit_test.rake +77 -0
  93. data/tasks/yard.rake +51 -0
  94. metadata +282 -0
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Union do
5
+
6
+ let(:operator_class){ Union }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:left) {[
10
+ {:city => 'London'},
11
+ {:city => 'Paris'},
12
+ {:city => 'Paris'}
13
+ ]}
14
+
15
+ let(:right) {[
16
+ {:city => 'Oslo'},
17
+ {:city => 'Paris'}
18
+ ]}
19
+
20
+ let(:operator){ Union.run([]) }
21
+ subject{ operator.to_a }
22
+
23
+ describe "when applied on non disjoint sets" do
24
+ before{ operator.datasets = [left, right] }
25
+ let(:expected){[
26
+ {:city => 'London'},
27
+ {:city => 'Paris'},
28
+ {:city => 'Oslo'}
29
+ ]}
30
+ it { should == expected }
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Unnest do
5
+
6
+ let(:operator_class){ Unnest }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:nested => {:a => "a", :b => "b"}, :c => "c"}
11
+ ]}
12
+
13
+ let(:expected) {[
14
+ {:a => "a", :b => "b", :c => "c"},
15
+ ]}
16
+
17
+ subject{ operator.to_a }
18
+
19
+ describe "when factored with commandline args" do
20
+ let(:operator){ Unnest.run(%w{-- nested}) }
21
+ before{ operator.pipe(input) }
22
+ it { should == expected }
23
+ end
24
+
25
+ describe "when factored with Lispy" do
26
+ let(:operator){ Lispy.unnest(input, :nested) }
27
+ it { should == expected }
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe Reader::AlfFile do
4
+
5
+ let(:io){ StringIO.new "(restrict :suppliers, lambda{status > 20})" }
6
+ let(:reader){ Reader::AlfFile.new(io, self) }
7
+ def dataset(name)
8
+ [{:status => 10},{:status => 30}]
9
+ end
10
+
11
+ subject{ reader.to_a }
12
+ it{ should == [{:status => 30}]}
13
+
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ {:id => 1}
2
+ {:id => 2}
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe Reader::Rash do
4
+
5
+ let(:lines){ [{:id => 1},{:id => 2}] }
6
+ let(:str) { lines.collect{|s| s.inspect}.join("\n") }
7
+ let(:io) { StringIO.new(str) }
8
+
9
+ describe "when called on a StringIO" do
10
+
11
+ let(:reader){ Reader::Rash.new(io) }
12
+
13
+ it "should be enumerable" do
14
+ reader.to_a.should == lines
15
+ end
16
+
17
+ end
18
+
19
+ describe "when called on a String" do
20
+
21
+ let(:file){ File.expand_path('../input.rb', __FILE__) }
22
+ let(:reader){ Reader::Rash.new(file) }
23
+
24
+ it "should be enumerable" do
25
+ reader.to_a.should == lines
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe Reader do
4
+
5
+ subject{ Reader }
6
+ it { should respond_to(:rash) }
7
+
8
+ describe "rash" do
9
+ subject{ Reader.rash($stdin) }
10
+ it{ should be_a(Reader::Rash) }
11
+ end
12
+
13
+ describe "reader" do
14
+
15
+ specify "when associated" do
16
+ r = Reader.reader('suppliers.rash')
17
+ r.should be_a(Reader::Rash)
18
+ end
19
+
20
+ specify "when not associated" do
21
+ lambda{ Reader.reader('.noone') }.should raise_error
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ class Renderer::Text
4
+ describe Cell do
5
+
6
+ let(:f){ Cell.new }
7
+
8
+ specify "text_rendering" do
9
+ Cell.new(100).text_rendering.should == "100"
10
+ Cell.new(:hello).text_rendering.should == ":hello"
11
+ Cell.new("hello").text_rendering.should == "hello"
12
+ Cell.new(10.0).text_rendering.should == "10.0000000"
13
+ Cell.new(10/3.0).text_rendering.should == "3.3333333"
14
+ Cell.new([]).text_rendering.should == "[]"
15
+ Cell.new([10/3.0, true]).text_rendering.should == "[3.3333333, true]"
16
+ end
17
+
18
+ specify "min_width" do
19
+ Cell.new("").min_width.should == 0
20
+ Cell.new(10/3.0).min_width.should == 9
21
+ Cell.new("12\n5345").min_width.should == 4
22
+ end
23
+
24
+ specify "rendering_lines" do
25
+ Cell.new("").rendering_lines.should == []
26
+ Cell.new(10/3.0).rendering_lines.should == ["3.3333333"]
27
+ Cell.new([10/3.0,true]).rendering_lines.should == ["[3.3333333, true]"]
28
+ Cell.new("abc").rendering_lines(5).should == ["abc "]
29
+ Cell.new(12).rendering_lines(5).should == [" 12"]
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ class Renderer::Text
4
+ describe Row do
5
+
6
+ let(:row){ Row.new(values) }
7
+
8
+ describe "when single values are used only" do
9
+
10
+ let(:values){ [ 10/3.0, true ] }
11
+ specify "rendering_lines" do
12
+ row.rendering_lines.should == ["| 3.3333333 | true |"]
13
+ row.rendering_lines([10,5]).should == ["| 3.3333333 | true |"]
14
+ end
15
+
16
+ end
17
+
18
+ describe "when multiple-line values are used" do
19
+
20
+ let(:values){ [ 10/3.0, [1, 2, 3] ] }
21
+
22
+ specify "rendering_lines" do
23
+ row.rendering_lines.should == ["| 3.3333333 | [1, 2, 3] |"]
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ class Renderer::Text
4
+ describe Table do
5
+
6
+ let(:columns){ [ :method, :total ] }
7
+ let(:table){ Table.new(records, columns) }
8
+
9
+ describe "on an empty table" do
10
+
11
+ let(:records){ [ ] }
12
+
13
+ specify "render" do
14
+ table.render.should == "+---------+--------+\n" +
15
+ "| :method | :total |\n" +
16
+ "+---------+--------+\n" +
17
+ "+---------+--------+\n"
18
+ end
19
+
20
+ end
21
+
22
+ describe "when single values are used only" do
23
+
24
+ let(:records){ [ [:by_x, 10.0], [:by_y, 2.0] ] }
25
+
26
+ specify "render" do
27
+ table.render.should == "+---------+------------+\n" +
28
+ "| :method | :total |\n" +
29
+ "+---------+------------+\n" +
30
+ "| :by_x | 10.0000000 |\n" +
31
+ "| :by_y | 2.0000000 |\n" +
32
+ "+---------+------------+\n"
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe Renderer do
4
+
5
+ subject{ Renderer }
6
+ it { should respond_to(:rash) }
7
+ it { should respond_to(:text) }
8
+
9
+ describe 'renderer' do
10
+ subject{ Renderer.renderer(:rash) }
11
+ it{ should be_a(Renderer) }
12
+ end
13
+
14
+ describe 'rash' do
15
+ subject{ Renderer.rash(input) }
16
+ let(:input){ [{:a => 1}] }
17
+ let(:output){ "" }
18
+ let(:expected){ "{:a=>1}\n" }
19
+ specify{
20
+ subject.should be_a(Renderer)
21
+ subject.execute(output).should == expected
22
+ }
23
+ end
24
+
25
+ describe 'text' do
26
+ subject{ Renderer.text(input) }
27
+ let(:input){ [{:a => 1}] }
28
+ let(:output){ "" }
29
+ let(:expected){ "+----+\n"\
30
+ "| :a |\n"\
31
+ "+----+\n"\
32
+ "| 1 |\n"\
33
+ "+----+\n"
34
+ }
35
+ specify{
36
+ subject.should be_a(Renderer)
37
+ subject.execute(output).should == expected
38
+ }
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'alf'
3
+
4
+ Alf::Lispy.extend(Alf::Lispy)
5
+
6
+ shared_examples_for "An operator class" do
7
+
8
+ it "should not have public set_args, _each and _prepare methods" do
9
+ operator_class.public_method_defined?(:set_args).should be_false
10
+ operator_class.public_method_defined?(:_each).should be_false
11
+ operator_class.public_method_defined?(:_prepare).should be_false
12
+ end
13
+
14
+ it "should have a public run method" do
15
+ operator_class.public_method_defined?(:run).should be_true
16
+ end
17
+
18
+ it "should have a public pipe method" do
19
+ operator_class.public_method_defined?(:pipe).should be_true
20
+ end
21
+
22
+ it "should have a public each method" do
23
+ operator_class.public_method_defined?(:each).should be_true
24
+ end
25
+
26
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Tools
4
+ describe OrderingKey do
5
+
6
+ describe "coerce" do
7
+
8
+ specify "when passed an doubly array" do
9
+ key = OrderingKey.coerce [[:a, :asc], [:b, :desc]]
10
+ key.attributes.should == [:a, :b]
11
+ key.order_of(:a).should == :asc
12
+ key.order_of(:b).should == :desc
13
+ end
14
+
15
+ specify "when passed a single array" do
16
+ key = OrderingKey.coerce [:a, :b]
17
+ key.attributes.should == [:a, :b]
18
+ key.order_of(:a).should == :asc
19
+ key.order_of(:b).should == :asc
20
+ end
21
+
22
+ specify "when passed an ordering key" do
23
+ key = OrderingKey.coerce [:a, :b]
24
+ key2 = OrderingKey.coerce key
25
+ key.should == key2
26
+ end
27
+
28
+ specify "when passed a projection key" do
29
+ pkey = ProjectionKey.new [:a, :b]
30
+ key = OrderingKey.coerce pkey
31
+ key.attributes.should == [:a, :b]
32
+ key.order_of(:a).should == :asc
33
+ key.order_of(:b).should == :asc
34
+ end
35
+
36
+ end # coerce
37
+
38
+ describe "compare" do
39
+
40
+ specify "when passed a single key" do
41
+ key = OrderingKey.coerce [:a]
42
+ key.compare({:a => 1}, {:a => 2}).should == -1
43
+ key.compare({:a => 1}, {:a => 1}).should == 0
44
+ key.compare({:a => 2}, {:a => 1}).should == 1
45
+ end
46
+
47
+ specify "when passed a single key with desc order" do
48
+ key = OrderingKey.coerce [[:a, :desc]]
49
+ key.compare({:a => 1}, {:a => 2}).should == 1
50
+ key.compare({:a => 1}, {:a => 1}).should == 0
51
+ key.compare({:a => 2}, {:a => 1}).should == -1
52
+ end
53
+
54
+ specify "when passed a double key" do
55
+ key = OrderingKey.coerce [[:a, :asc], [:b, :desc]]
56
+ key.compare({:a => 1, :b => 1}, {:a => 0, :b => 1}).should == 1
57
+ key.compare({:a => 1, :b => 1}, {:a => 1, :b => 2}).should == 1
58
+ key.compare({:a => 1, :b => 1}, {:a => 1, :b => 1}).should == 0
59
+ end
60
+
61
+ end
62
+
63
+ describe "+" do
64
+
65
+ specify "when passed another key" do
66
+ key = OrderingKey.coerce [:a]
67
+ key2 = key + OrderingKey.coerce([[:b, :desc]])
68
+ key2.ordering.should == [[:a, :asc], [:b, :desc]]
69
+ end
70
+
71
+ specify "when passed another array" do
72
+ key = OrderingKey.coerce [:a]
73
+ key2 = key + [[:b, :desc]]
74
+ key2.ordering.should == [[:a, :asc], [:b, :desc]]
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Tools
4
+ describe ProjectionKey do
5
+
6
+ describe "coerce" do
7
+
8
+ specify "when passed an array" do
9
+ key = ProjectionKey.coerce [:a, :b]
10
+ key.attributes.should == [:a, :b]
11
+ key.allbut.should == false
12
+ end
13
+
14
+ specify "when passed a ProjectionKey" do
15
+ key = ProjectionKey.coerce [:a, :b]
16
+ key2 = ProjectionKey.coerce key
17
+ key2.should == key
18
+ end
19
+
20
+ specify "when passed an OrderingKey" do
21
+ okey = OrderingKey.new [[:a, :asc], [:b, :asc]]
22
+ key = ProjectionKey.coerce(okey)
23
+ key.attributes.should == [:a, :b]
24
+ key.allbut.should == false
25
+ end
26
+
27
+ end
28
+
29
+ describe "to_ordering_key" do
30
+
31
+ specify "when passed an array" do
32
+ key = ProjectionKey.coerce [:a, :b]
33
+ okey = key.to_ordering_key
34
+ okey.attributes.should == [:a, :b]
35
+ okey.order_of(:a).should == :asc
36
+ okey.order_of(:b).should == :asc
37
+ end
38
+
39
+ end
40
+
41
+ describe "split" do
42
+
43
+ subject{ key.split(tuple) }
44
+
45
+ describe "when used without allbut" do
46
+ let(:key){ ProjectionKey.new [:a, :b] }
47
+ let(:tuple){ {:a => 1, :b => 2, :c => 3} }
48
+ let(:expected){ [{:a => 1, :b => 2}, {:c => 3}] }
49
+ it{ should == expected }
50
+ end
51
+
52
+ describe "when used with allbut" do
53
+ let(:key){ ProjectionKey.new [:a, :b], true }
54
+ let(:tuple){ {:a => 1, :b => 2, :c => 3} }
55
+ let(:expected){ [{:c => 3}, {:a => 1, :b => 2}] }
56
+ it{ should == expected }
57
+ end
58
+
59
+ end
60
+
61
+ describe "project" do
62
+
63
+ subject{ key.project(tuple) }
64
+
65
+ describe "when used without allbut" do
66
+ let(:key){ ProjectionKey.new [:a, :b] }
67
+ let(:tuple){ {:a => 1, :b => 2, :c => 3} }
68
+ let(:expected){ {:a => 1, :b => 2} }
69
+ it{ should == expected }
70
+ end
71
+
72
+ describe "when used with allbut" do
73
+ let(:key){ ProjectionKey.new [:a, :b], true }
74
+ let(:tuple){ {:a => 1, :b => 2, :c => 3} }
75
+ let(:expected){ {:c => 3} }
76
+ it{ should == expected }
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+ end
83
+ end