alf 0.9.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 (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