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,63 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Join::HashBased do
5
+
6
+ let(:suppliers) {[
7
+ {:sid => 'S1', :city => 'London'},
8
+ {:sid => 'S2', :city => 'Paris'},
9
+ {:sid => 'S3', :city => 'Paris'}
10
+ ]}
11
+
12
+ let(:statuses) {[
13
+ {:sid => 'S1', :status => 20},
14
+ {:sid => 'S2', :status => 10},
15
+ {:sid => 'S3', :status => 30}
16
+ ]}
17
+
18
+ let(:countries) {[
19
+ {:city => 'London', :country => 'England'},
20
+ {:city => 'Paris', :country => 'France'},
21
+ {:city => 'Bruxelles', :country => 'Belgium (until ?)'}
22
+ ]}
23
+
24
+ let(:operator){ Join::HashBased.new }
25
+ subject{ operator.to_a }
26
+
27
+ describe "when applied on both candidate keys" do
28
+ before{ operator.datasets = [suppliers, statuses] }
29
+ let(:expected){[
30
+ {:sid => 'S1', :city => 'London', :status => 20},
31
+ {:sid => 'S2', :city => 'Paris', :status => 10},
32
+ {:sid => 'S3', :city => 'Paris', :status => 30}
33
+ ]}
34
+ it { should == expected }
35
+ end
36
+
37
+ describe "when applied on a typical foreign key" do
38
+ let(:expected){[
39
+ {:sid => 'S1', :city => 'London', :country => 'England'},
40
+ {:sid => 'S2', :city => 'Paris', :country => 'France'},
41
+ {:sid => 'S3', :city => 'Paris', :country => 'France'}
42
+ ]}
43
+ describe "on one way" do
44
+ before{ operator.datasets = [suppliers, countries] }
45
+ it { should == expected }
46
+ end
47
+ describe "on the other way around" do
48
+ before{ operator.datasets = [countries, suppliers] }
49
+ it { should == expected }
50
+ end
51
+ end
52
+
53
+ describe "when no attributes are in common" do
54
+ before{ operator.datasets = [statuses, countries] }
55
+ let(:expected){
56
+ statuses.collect{|s| countries.collect{|c| c.merge(s)}}.flatten
57
+ }
58
+ it { should == expected }
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Minus do
5
+
6
+ let(:operator_class){ Minus }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:left) {[
10
+ {:sid => 'S1', :city => 'London'},
11
+ {:sid => 'S2', :city => 'Paris'},
12
+ {:sid => 'S3', :city => 'Paris'}
13
+ ]}
14
+
15
+ let(:right) {[
16
+ {:sid => 'S2', :city => 'Paris'},
17
+ {:sid => 'S1', :city => 'London'},
18
+ ]}
19
+
20
+ let(:disjoint) {[
21
+ {:sid => 'S4', :city => 'Oslo'},
22
+ {:sid => 'S5', :city => 'Bruxelles'},
23
+ ]}
24
+
25
+ let(:operator){ Minus.run([]) }
26
+ subject{ operator.to_a }
27
+
28
+ describe "when applied on the same operand twice" do
29
+ before{ operator.datasets = [left, left] }
30
+ it { should be_empty }
31
+ end
32
+
33
+ describe "when applied on operands sharing tuples" do
34
+ before{ operator.datasets = [left, right] }
35
+ let(:expected) {[
36
+ {:sid => 'S3', :city => 'Paris'}
37
+ ]}
38
+ it { should == expected }
39
+ end
40
+
41
+ describe "when applied on disjoint operands" do
42
+ before{ operator.datasets = [left, disjoint] }
43
+ it { should == left }
44
+ end
45
+
46
+ describe "when factored with Lispy" do
47
+ let(:operator){ Lispy.minus(left, right) }
48
+ let(:expected) {[
49
+ {:sid => 'S3', :city => 'Paris'}
50
+ ]}
51
+ it { should == expected }
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Nest do
5
+
6
+ let(:operator_class){ Nest }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:a => "a", :b => "b", :c => "c"},
11
+ ]}
12
+
13
+ let(:expected) {[
14
+ {:nested => {: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){ Nest.run(["--", "a", "b", "nested"]) }
21
+ before{ operator.pipe(input) }
22
+ it { should == expected }
23
+ end
24
+
25
+ describe "when factored with Lispy" do
26
+ let(:operator){ Lispy.nest(input, [:a, :b], :nested) }
27
+ it { should == expected }
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Project do
5
+
6
+ let(:operator_class){ Project }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:a => "a", :b => "b"},
11
+ {:a => "a", :b => "b"},
12
+ ]}
13
+
14
+ subject{ operator.to_a }
15
+
16
+ describe "when used without --allbut" do
17
+ let(:expected){[{:a => "a"}]}
18
+
19
+ describe "and factored with commandline args" do
20
+ let(:operator){ Project.run(["--", 'a']) }
21
+ before{ operator.pipe(input) }
22
+ it { should == expected }
23
+ end
24
+
25
+ describe "and factored with Lispy" do
26
+ let(:operator){ Lispy.project(input, [:a]) }
27
+ it { should == expected }
28
+ end
29
+
30
+ end # --no-allbut
31
+
32
+ describe "when used with --allbut" do
33
+ let(:expected){[{:b => "b"}]}
34
+
35
+ describe "and factored with commandline args" do
36
+ let(:operator){ Project.run(['--allbut', '--', 'a']) }
37
+ before{ operator.pipe(input) }
38
+ it { should == expected }
39
+ end
40
+
41
+ describe "and factored with Lispy" do
42
+ let(:operator){ Lispy.allbut(input, [:a]) }
43
+ it { should == expected }
44
+ end
45
+
46
+ end # --allbut
47
+
48
+ describe "when all is projected" do
49
+ let(:expected){[{}]}
50
+
51
+ describe "when input is not empty" do
52
+ let(:operator){ Lispy.project(input, []) }
53
+ it { should == expected }
54
+ end
55
+
56
+ describe "when input is empty" do
57
+ let(:operator){ Lispy.project([], []) }
58
+ it { should == [] }
59
+ end
60
+
61
+ end # all attributes projected
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Quota do
5
+
6
+ let(:operator_class){ Quota }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:a => "via_method", :time => 1},
11
+ {:a => "via_method", :time => 2},
12
+ {:a => "via_method", :time => 3},
13
+ {:a => "via_reader", :time => 4},
14
+ {:a => "via_reader", :time => 2},
15
+ ]}
16
+
17
+ let(:expected) {[
18
+ {:a => "via_method", :time => 1, :time_sum => 1, :time_max => 1},
19
+ {:a => "via_method", :time => 2, :time_sum => 3, :time_max => 2},
20
+ {:a => "via_method", :time => 3, :time_sum => 6, :time_max => 3},
21
+ {:a => "via_reader", :time => 2, :time_sum => 2, :time_max => 2},
22
+ {:a => "via_reader", :time => 4, :time_sum => 6, :time_max => 4},
23
+ ]}
24
+
25
+ subject{ operator.to_a }
26
+
27
+ describe "When factored with commandline args" do
28
+ let(:opts){ ['--by=a', "--order=time"] }
29
+ let(:aggs){ ["time_sum", "sum(:time)", "time_max", "max(:time)"] }
30
+ let(:operator){ Quota.run(opts + ["--"] + aggs) }
31
+ before{ operator.pipe(input) }
32
+ it { should == expected }
33
+ end
34
+
35
+ describe "When factored with Lispy" do
36
+ let(:aggs){{:time_sum => Aggregator.sum(:time),
37
+ :time_max => Aggregator.max(:time)}}
38
+ let(:operator){ Lispy.quota(input, [:a], [:time], aggs) }
39
+ it { should == expected }
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Rename do
5
+
6
+ let(:operator_class){ Rename }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:a => "a", :b => "b"},
11
+ ]}
12
+
13
+ let(:expected){[
14
+ {:z => "a", :b => "b"},
15
+ ]}
16
+
17
+ subject{ operator.to_a }
18
+
19
+ describe "When factored with Lispy" do
20
+ let(:operator){ Lispy.rename(input, {:a => :z}) }
21
+ it{ should == expected }
22
+ end
23
+
24
+ describe "When factored from commandline args" do
25
+ let(:operator){ Rename.run(['--', 'a', 'z']) }
26
+ before{ operator.pipe(input) }
27
+ it{ should == expected }
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Restrict do
5
+
6
+ let(:operator_class){ Restrict }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:tested => 1, :other => "b"},
11
+ {:tested => 30, :other => "a"},
12
+ ]}
13
+
14
+ let(:expected){[
15
+ {:tested => 1, :other => "b"}
16
+ ]}
17
+
18
+ subject{ operator.to_a }
19
+
20
+ describe "when used with no argument" do
21
+ let(:operator){ Restrict.run(%w{}) }
22
+ before{ operator.pipe(input) }
23
+ it { should == input }
24
+ end
25
+
26
+ describe "when used with a string" do
27
+ describe "when factored with commandline args" do
28
+ let(:operator){ Restrict.run(["--", "tested < 10"]) }
29
+ before{ operator.pipe(input) }
30
+ it { should == expected }
31
+ end
32
+ describe "when factored with Lispy" do
33
+ let(:operator){ Lispy.restrict(input, "tested < 10") }
34
+ it { should == expected }
35
+ end
36
+ end
37
+
38
+ describe "when used with arguments" do
39
+ describe "when factored with commandline args" do
40
+ let(:operator){ Restrict.run(["--", "tested", "1"]) }
41
+ before{ operator.pipe(input) }
42
+ it { should == expected }
43
+ end
44
+ describe "when factored with Lispy and Proc" do
45
+ let(:operator){ Lispy.restrict(input, lambda{ tested < 10 }) }
46
+ it { should == expected }
47
+ end
48
+ describe "when factored with Lispy and array" do
49
+ let(:operator){ Lispy.restrict(input, [:tested, 1]) }
50
+ it { should == expected }
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Summarize::SortBased do
5
+
6
+ let(:input) {[
7
+ {:a => "via_method", :time => 1},
8
+ {:a => "via_method", :time => 1},
9
+ {:a => "via_method", :time => 2},
10
+ {:a => "via_reader", :time => 4},
11
+ {:a => "via_reader", :time => 2},
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(:by_key){ Tools::ProjectionKey.new([:a],false) }
20
+ let(:aggs){{:time_sum => Aggregator.sum(:time),
21
+ :time_max => Aggregator.max(:time)}}
22
+ let(:operator){ Summarize::SortBased.new(by_key, aggs) }
23
+
24
+ before{ operator.pipe(input) }
25
+ subject{ operator.to_a }
26
+
27
+ it { should == expected }
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
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},
19
+ {:a => "via_reader", :time_sum => 6, :time_max => 4},
20
+ ]}
21
+
22
+ subject{ operator.to_a }
23
+
24
+ describe "When factored with commandline args" do
25
+ let(:opts){ ["--by=a"] }
26
+ let(:aggs){ ["time_sum", "sum(:time)", "time_max", "max(:time)"] }
27
+ let(:operator){ Summarize.run(opts + ["--"] +aggs) }
28
+ before{ operator.pipe(input) }
29
+ it { should == expected }
30
+ end
31
+
32
+ describe "When factored with Lispy" do
33
+ let(:aggs){{:time_sum => Aggregator.sum(:time),
34
+ :time_max => Aggregator.max(:time)}}
35
+ let(:operator){ Lispy.summarize(input, [:a], aggs) }
36
+ it { should == expected }
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator::Relational
4
+ describe Ungroup do
5
+
6
+ let(:operator_class){ Ungroup }
7
+ it_should_behave_like("An operator class")
8
+
9
+ let(:input) {[
10
+ {:a => "via_method", :as => [{:time => 1, :b => "b"}, {:time => 2, :b => "b"}]},
11
+ {:a => "via_reader", :as => [{:time => 3, :b => "b"}]},
12
+ ]}
13
+
14
+ let(:expected) {[
15
+ {:a => "via_method", :time => 1, :b => "b"},
16
+ {:a => "via_method", :time => 2, :b => "b"},
17
+ {:a => "via_reader", :time => 3, :b => "b"},
18
+ ]}
19
+
20
+ subject{ operator.to_a.sort{|k1,k2| k1[:time] <=> k2[:time]} }
21
+
22
+ describe "when factored with commandline args" do
23
+ let(:operator) { Ungroup.run(%w{-- as}) }
24
+ before{ operator.pipe(input) }
25
+ it { should == expected }
26
+ end
27
+
28
+ describe "when factored with Lispy" do
29
+ let(:operator) { Lispy.ungroup(input, :as) }
30
+ it { should == expected }
31
+ end
32
+
33
+ end
34
+ end
35
+ end