alf 0.9.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (270) hide show
  1. data/CHANGELOG.md +255 -129
  2. data/Gemfile +31 -1
  3. data/Gemfile.lock +17 -20
  4. data/LICENCE.md +1 -1
  5. data/Manifest.txt +2 -0
  6. data/README.md +37 -43
  7. data/TODO.md +1 -1
  8. data/alf.gemspec +10 -7
  9. data/alf.noespec +24 -13
  10. data/bin/alf +2 -2
  11. data/doc/commands/exec.md +16 -0
  12. data/doc/commands/help.md +11 -0
  13. data/doc/commands/main.md +33 -0
  14. data/doc/commands/show.md +19 -0
  15. data/doc/operators/non_relational/autonum.md +23 -0
  16. data/doc/operators/non_relational/clip.md +31 -0
  17. data/doc/operators/non_relational/coerce.md +15 -0
  18. data/doc/operators/non_relational/compact.md +20 -0
  19. data/doc/operators/non_relational/defaults.md +32 -0
  20. data/doc/operators/non_relational/generator.md +20 -0
  21. data/doc/operators/non_relational/sort.md +24 -0
  22. data/doc/operators/relational/extend.md +18 -0
  23. data/doc/operators/relational/group.md +27 -0
  24. data/doc/operators/relational/intersect.md +13 -0
  25. data/doc/operators/relational/join.md +27 -0
  26. data/doc/operators/relational/matching.md +20 -0
  27. data/doc/operators/relational/minus.md +12 -0
  28. data/doc/operators/relational/not-matching.md +20 -0
  29. data/doc/operators/relational/project.md +28 -0
  30. data/doc/operators/relational/quota.md +21 -0
  31. data/doc/operators/relational/rank.md +27 -0
  32. data/doc/operators/relational/rename.md +17 -0
  33. data/doc/operators/relational/restrict.md +25 -0
  34. data/doc/operators/relational/summarize.md +25 -0
  35. data/doc/operators/relational/ungroup.md +20 -0
  36. data/doc/operators/relational/union.md +14 -0
  37. data/doc/operators/relational/unwrap.md +20 -0
  38. data/doc/operators/relational/wrap.md +24 -0
  39. data/examples/csv/suppliers.csv +6 -0
  40. data/examples/logs/access.log +1000 -0
  41. data/examples/logs/combined.alf +2 -0
  42. data/examples/logs/hits.alf +14 -0
  43. data/examples/logs/not_found.alf +7 -0
  44. data/examples/logs/robots-cheating.alf +11 -0
  45. data/examples/logs/robots.alf +8 -0
  46. data/examples/northwind/customers.csv +92 -0
  47. data/examples/northwind/northwind.db +0 -0
  48. data/examples/northwind/orders.csv +831 -0
  49. data/examples/operators/clip.alf +1 -1
  50. data/examples/operators/database.alf +5 -6
  51. data/examples/operators/defaults.alf +1 -1
  52. data/examples/operators/group.alf +1 -1
  53. data/examples/operators/project.alf +2 -1
  54. data/examples/operators/pseudo-with.alf +2 -2
  55. data/examples/operators/quota.alf +2 -2
  56. data/examples/operators/summarize.alf +2 -2
  57. data/lib/alf/aggregator/aggregators.rb +77 -0
  58. data/lib/alf/aggregator/base.rb +95 -0
  59. data/lib/alf/aggregator/class_methods.rb +57 -0
  60. data/lib/alf/buffer/sorted.rb +48 -0
  61. data/lib/alf/command/class_methods.rb +27 -0
  62. data/lib/alf/command/doc_manager.rb +72 -0
  63. data/lib/alf/command/exec.rb +12 -0
  64. data/lib/alf/command/help.rb +31 -0
  65. data/lib/alf/command/main.rb +146 -0
  66. data/lib/alf/command/show.rb +33 -0
  67. data/lib/alf/environment/base.rb +37 -0
  68. data/lib/alf/environment/class_methods.rb +93 -0
  69. data/lib/alf/environment/explicit.rb +38 -0
  70. data/lib/alf/environment/folder.rb +62 -0
  71. data/lib/alf/extra/csv.rb +104 -0
  72. data/lib/alf/extra/logs.rb +100 -0
  73. data/lib/alf/extra/sequel.rb +77 -0
  74. data/lib/alf/{yaml.rb → extra/yaml.rb} +0 -0
  75. data/lib/alf/extra.rb +5 -0
  76. data/lib/alf/iterator/base.rb +38 -0
  77. data/lib/alf/iterator/class_methods.rb +22 -0
  78. data/lib/alf/iterator/proxy.rb +33 -0
  79. data/lib/alf/lispy/instance_methods.rb +157 -0
  80. data/lib/alf/operator/base.rb +74 -0
  81. data/lib/alf/operator/binary.rb +32 -0
  82. data/lib/alf/operator/cesure.rb +45 -0
  83. data/lib/alf/operator/class_methods.rb +132 -0
  84. data/lib/alf/operator/experimental.rb +9 -0
  85. data/lib/alf/operator/non_relational/autonum.rb +24 -0
  86. data/lib/alf/operator/non_relational/clip.rb +20 -0
  87. data/lib/alf/operator/non_relational/coerce.rb +21 -0
  88. data/lib/alf/operator/non_relational/compact.rb +62 -0
  89. data/lib/alf/operator/non_relational/defaults.rb +25 -0
  90. data/lib/alf/operator/non_relational/generator.rb +38 -0
  91. data/lib/alf/operator/non_relational/sort.rb +23 -0
  92. data/lib/alf/operator/nullary.rb +20 -0
  93. data/lib/alf/operator/relational/extend.rb +24 -0
  94. data/lib/alf/operator/relational/group.rb +32 -0
  95. data/lib/alf/operator/relational/intersect.rb +37 -0
  96. data/lib/alf/operator/relational/join.rb +106 -0
  97. data/lib/alf/operator/relational/matching.rb +45 -0
  98. data/lib/alf/operator/relational/minus.rb +37 -0
  99. data/lib/alf/operator/relational/not_matching.rb +45 -0
  100. data/lib/alf/operator/relational/project.rb +22 -0
  101. data/lib/alf/operator/relational/quota.rb +51 -0
  102. data/lib/alf/operator/relational/rank.rb +55 -0
  103. data/lib/alf/operator/relational/rename.rb +19 -0
  104. data/lib/alf/operator/relational/restrict.rb +20 -0
  105. data/lib/alf/operator/relational/summarize.rb +83 -0
  106. data/lib/alf/operator/relational/ungroup.rb +25 -0
  107. data/lib/alf/operator/relational/union.rb +32 -0
  108. data/lib/alf/operator/relational/unwrap.rb +21 -0
  109. data/lib/alf/operator/relational/wrap.rb +22 -0
  110. data/lib/alf/operator/shortcut.rb +53 -0
  111. data/lib/alf/operator/signature.rb +262 -0
  112. data/lib/alf/operator/transform.rb +27 -0
  113. data/lib/alf/operator/unary.rb +38 -0
  114. data/lib/alf/reader/alf_file.rb +24 -0
  115. data/lib/alf/reader/base.rb +119 -0
  116. data/lib/alf/reader/class_methods.rb +82 -0
  117. data/lib/alf/reader/rash.rb +28 -0
  118. data/lib/alf/relation/class_methods.rb +37 -0
  119. data/lib/alf/relation/instance_methods.rb +127 -0
  120. data/lib/alf/renderer/base.rb +72 -0
  121. data/lib/alf/renderer/class_methods.rb +58 -0
  122. data/lib/alf/renderer/rash.rb +19 -0
  123. data/lib/alf/{text.rb → renderer/text.rb} +1 -1
  124. data/lib/alf/tools/coerce.rb +14 -0
  125. data/lib/alf/tools/miscellaneous.rb +77 -0
  126. data/lib/alf/tools/to_lispy.rb +99 -0
  127. data/lib/alf/tools/to_ruby_literal.rb +14 -0
  128. data/lib/alf/tools/tuple_handle.rb +50 -0
  129. data/lib/alf/types/attr_list.rb +56 -0
  130. data/lib/alf/types/attr_name.rb +28 -0
  131. data/lib/alf/types/boolean.rb +12 -0
  132. data/lib/alf/types/heading.rb +96 -0
  133. data/lib/alf/types/ordering.rb +93 -0
  134. data/lib/alf/types/renaming.rb +57 -0
  135. data/lib/alf/types/summarization.rb +76 -0
  136. data/lib/alf/types/tuple_computation.rb +61 -0
  137. data/lib/alf/types/tuple_expression.rb +61 -0
  138. data/lib/alf/types/tuple_predicate.rb +49 -0
  139. data/lib/alf/version.rb +2 -2
  140. data/lib/alf.rb +193 -3714
  141. data/spec/integration/__database__/group.alf +1 -1
  142. data/spec/integration/__database__/suppliers_csv.csv +6 -0
  143. data/spec/integration/command/alf/alf.db +0 -0
  144. data/spec/integration/command/alf/alf_env_sqlite.cmd +1 -0
  145. data/spec/integration/command/alf/alf_env_sqlite.stdout +9 -0
  146. data/spec/integration/command/alf/alf_help.cmd +1 -0
  147. data/spec/integration/command/alf/alf_help.stdout +67 -0
  148. data/spec/integration/command/autonum/autonum_0.cmd +1 -1
  149. data/spec/integration/command/coerce/coerce_1.cmd +1 -0
  150. data/spec/integration/command/coerce/coerce_1.stdout +5 -0
  151. data/spec/integration/command/defaults/defaults_0.cmd +1 -1
  152. data/spec/integration/command/defaults/defaults_0.stdout +9 -9
  153. data/spec/integration/command/defaults/defaults_2.cmd +1 -0
  154. data/spec/integration/command/defaults/defaults_2.stdout +9 -0
  155. data/spec/integration/command/generator/generator_1.cmd +1 -0
  156. data/spec/integration/command/generator/generator_1.stdout +10 -0
  157. data/spec/integration/command/generator/generator_2.cmd +1 -0
  158. data/spec/integration/command/generator/generator_2.stdout +5 -0
  159. data/spec/integration/command/generator/generator_3.cmd +1 -0
  160. data/spec/integration/command/generator/generator_3.stdout +5 -0
  161. data/spec/integration/command/group/group_0.cmd +1 -1
  162. data/spec/integration/command/group/group_1.cmd +1 -1
  163. data/spec/integration/command/help/help_1.cmd +1 -0
  164. data/spec/integration/command/help/help_1.stdout +22 -0
  165. data/spec/integration/command/quota/quota_0.cmd +1 -1
  166. data/spec/integration/command/rank/rank_1.cmd +1 -1
  167. data/spec/integration/command/rank/rank_1.stdout +10 -10
  168. data/spec/integration/command/rank/rank_2.cmd +1 -1
  169. data/spec/integration/command/rank/rank_2.stdout +10 -10
  170. data/spec/integration/command/rank/rank_3.cmd +1 -1
  171. data/spec/integration/command/rank/rank_3.stdout +10 -10
  172. data/spec/integration/command/rank/rank_4.cmd +1 -1
  173. data/spec/integration/command/rank/rank_5.cmd +1 -1
  174. data/spec/integration/command/show/show_csv.cmd +1 -0
  175. data/spec/integration/command/show/show_csv.stdout +6 -0
  176. data/spec/integration/command/show/show_rash_2.cmd +1 -1
  177. data/spec/integration/command/show/show_rash_2.stdout +5 -5
  178. data/spec/integration/command/sort/sort_0.cmd +1 -1
  179. data/spec/integration/command/sort/sort_1.cmd +1 -1
  180. data/spec/integration/command/sort/sort_1.stdout +2 -2
  181. data/spec/integration/command/sort/sort_2.cmd +1 -0
  182. data/spec/integration/command/sort/sort_2.stdout +9 -0
  183. data/spec/integration/command/sort/sort_3.cmd +1 -0
  184. data/spec/integration/command/sort/sort_3.stdout +9 -0
  185. data/spec/integration/command/summarize/summarize_0.cmd +1 -1
  186. data/spec/integration/command/ungroup/ungroup_0.cmd +1 -1
  187. data/spec/integration/command/wrap/wrap_0.cmd +1 -1
  188. data/spec/integration/semantics/test_project.alf +5 -6
  189. data/spec/integration/semantics/test_rank.alf +16 -16
  190. data/spec/integration/test_command.rb +17 -6
  191. data/spec/integration/test_examples.rb +1 -1
  192. data/spec/regression/logs/apache_combined.log +5 -0
  193. data/spec/regression/logs/test_path_attribute.rb +25 -0
  194. data/spec/regression/relation/test_relation_allbut_all.rb +14 -0
  195. data/spec/shared/an_operator_class.rb +10 -5
  196. data/spec/spec_helper.rb +1 -7
  197. data/spec/unit/assumptions/test_set.rb +64 -0
  198. data/spec/unit/command/doc_manager/dynamic.md +1 -0
  199. data/spec/unit/command/doc_manager/example.md +1 -0
  200. data/spec/unit/command/doc_manager/example_1.txt +11 -0
  201. data/spec/unit/command/doc_manager/static.md +1 -0
  202. data/spec/unit/command/doc_manager/test_call.rb +49 -0
  203. data/spec/unit/csv/input.csv +3 -0
  204. data/spec/unit/csv/test_reader.rb +66 -0
  205. data/spec/unit/csv/test_renderer.rb +73 -0
  206. data/spec/unit/lispy/test_relation.rb +37 -0
  207. data/spec/unit/lispy/test_run.rb +40 -0
  208. data/spec/unit/lispy/test_tuple.rb +36 -0
  209. data/spec/unit/logs/apache_combined.log +5 -0
  210. data/spec/unit/logs/postgresql.log +29 -0
  211. data/spec/unit/logs/test_reader.rb +56 -0
  212. data/spec/unit/operator/non_relational/compact/{buffer_based.rb → test_buffer_based.rb} +0 -0
  213. data/spec/unit/operator/non_relational/test_clip.rb +1 -1
  214. data/spec/unit/operator/non_relational/test_coerce.rb +35 -0
  215. data/spec/unit/operator/non_relational/test_defaults.rb +15 -2
  216. data/spec/unit/operator/non_relational/test_generator.rb +78 -0
  217. data/spec/unit/operator/relational/join/test_hash_based.rb +4 -4
  218. data/spec/unit/operator/relational/matching/test_hash_based.rb +6 -6
  219. data/spec/unit/operator/relational/not_matching/test_hash_based.rb +4 -4
  220. data/spec/unit/operator/relational/summarize/test_hash_based.rb +10 -6
  221. data/spec/unit/operator/relational/summarize/test_sort_based.rb +18 -7
  222. data/spec/unit/operator/relational/test_group.rb +8 -8
  223. data/spec/unit/operator/relational/test_intersect.rb +3 -3
  224. data/spec/unit/operator/relational/test_minus.rb +3 -3
  225. data/spec/unit/operator/relational/test_project.rb +12 -2
  226. data/spec/unit/operator/relational/test_quota.rb +5 -6
  227. data/spec/unit/operator/relational/test_summarize.rb +9 -11
  228. data/spec/unit/operator/relational/test_union.rb +1 -1
  229. data/spec/unit/operator/relational/test_wrap.rb +1 -1
  230. data/spec/unit/operator/signature/test_collect_on.rb +45 -0
  231. data/spec/unit/operator/signature/test_initialize.rb +17 -0
  232. data/spec/unit/operator/signature/test_install.rb +56 -0
  233. data/spec/unit/operator/signature/test_option_parser.rb +36 -0
  234. data/spec/unit/operator/signature/test_parse_args.rb +60 -0
  235. data/spec/unit/operator/signature/test_parse_argv.rb +87 -0
  236. data/spec/unit/operator/signature/test_to_lispy.rb +102 -0
  237. data/spec/unit/operator/signature/test_to_shell.rb +103 -0
  238. data/spec/unit/operator/test_non_relational.rb +3 -1
  239. data/spec/unit/relation/test_relops.rb +20 -15
  240. data/spec/unit/sequel/alf.db +0 -0
  241. data/spec/unit/sequel/test_environment.rb +54 -0
  242. data/spec/unit/test_aggregator.rb +32 -22
  243. data/spec/unit/test_environment.rb +5 -0
  244. data/spec/unit/test_lispy.rb +4 -0
  245. data/spec/unit/test_relation.rb +5 -0
  246. data/spec/unit/text/test_cell.rb +6 -6
  247. data/spec/unit/text/test_row.rb +3 -3
  248. data/spec/unit/text/test_table.rb +6 -6
  249. data/spec/unit/tools/test_coalesce.rb +15 -0
  250. data/spec/unit/tools/test_coerce.rb +10 -0
  251. data/spec/unit/tools/test_to_lispy.rb +138 -0
  252. data/spec/unit/tools/test_to_ruby_literal.rb +10 -0
  253. data/spec/unit/tools/test_tuple_handle.rb +1 -59
  254. data/spec/unit/types/test_attr_list.rb +106 -0
  255. data/spec/unit/types/test_attr_name.rb +52 -0
  256. data/spec/unit/{test_heading.rb → types/test_heading.rb} +10 -0
  257. data/spec/unit/types/test_ordering.rb +127 -0
  258. data/spec/unit/types/test_renaming.rb +55 -0
  259. data/spec/unit/types/test_summarization.rb +63 -0
  260. data/spec/unit/types/test_tuple_computation.rb +60 -0
  261. data/spec/unit/types/test_tuple_expression.rb +64 -0
  262. data/spec/unit/types/test_tuple_predicate.rb +79 -0
  263. data/tasks/debug_mail.rake +1 -1
  264. data/tasks/debug_mail.txt +5 -0
  265. data/tasks/gh-pages.rake +63 -0
  266. metadata +325 -52
  267. data/spec/unit/operator/test_command_methods.rb +0 -38
  268. data/spec/unit/tools/test_ordering_key.rb +0 -94
  269. data/spec/unit/tools/test_parse_commandline_args.rb +0 -47
  270. data/spec/unit/tools/test_projection_key.rb +0 -83
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator
4
+ describe Signature, "#parse_argv" do
5
+
6
+ let(:clazz){ Class.new(Object) }
7
+ let(:receiver){ clazz.new }
8
+ before{
9
+ signature.install
10
+ }
11
+ subject{
12
+ signature.parse_argv(argv, receiver)
13
+ }
14
+
15
+ describe "on a singleton signature with a AttrList" do
16
+ let(:signature){
17
+ Signature.new(clazz) do |s|
18
+ s.argument :proj, AttrList
19
+ end
20
+ }
21
+ let(:argv){ %w{-- hello world} }
22
+ specify{
23
+ subject.should eq([])
24
+ receiver.proj.should eq(AttrList.new([:hello, :world]))
25
+ }
26
+ end
27
+
28
+ describe "on a singleton signature with a default" do
29
+ let(:signature){
30
+ Signature.new(clazz) do |s|
31
+ s.argument :attrname, AttrName, :autonum
32
+ end
33
+ }
34
+ let(:argv){ %w{} }
35
+ specify{
36
+ subject.should eq([])
37
+ receiver.attrname.should eq(:autonum)
38
+ }
39
+ end
40
+
41
+ describe "On quota signature" do
42
+ let(:signature){
43
+ Signature.new(clazz) do |s|
44
+ s.argument :by, AttrList, []
45
+ s.argument :order, Ordering, []
46
+ s.argument :summarization, Summarization, {}
47
+ end
48
+ }
49
+ let(:argv){ %w|op1 -- a -- time -- time_sum sum{time} time_max max{time}| }
50
+ specify{
51
+ subject.should eq(["op1"])
52
+ receiver.by.should eq(AttrList.new([:a]))
53
+ receiver.order.should eq(Ordering.coerce([:time]))
54
+ }
55
+ end
56
+
57
+ describe "When signature contains options" do
58
+ let(:signature){
59
+ Signature.new(clazz) do |s|
60
+ s.argument :by, AttrList, []
61
+ s.option :allbut, Boolean, false, "Allbut?"
62
+ end
63
+ }
64
+
65
+ describe "when options are specified" do
66
+ let(:argv){ %w{op1 --allbut -- a} }
67
+ specify{
68
+ subject.should eq(["op1"])
69
+ receiver.by.should eq(AttrList.new([:a]))
70
+ receiver.allbut.should eql(true)
71
+ }
72
+ end
73
+
74
+ describe "when options are not specified" do
75
+ let(:argv){ %w{op1 -- a} }
76
+ specify{
77
+ subject.should eq(["op1"])
78
+ receiver.by.should eq(AttrList.new([:a]))
79
+ receiver.allbut.should eql(false)
80
+ }
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator
4
+ describe Signature, '#to_lispy' do
5
+
6
+ subject{ signature.to_lispy }
7
+
8
+ describe "on a nullary signature" do
9
+ let(:clazz){ Operator::NonRelational::Generator }
10
+
11
+ describe "on an empty signature" do
12
+ let(:signature){ Signature.new(clazz){|s|} }
13
+ it{ should eq("(generator)") }
14
+ end
15
+
16
+ describe "on an option-only signature" do
17
+ let(:signature){
18
+ Signature.new(clazz) do |s|
19
+ s.option :allbut, Boolean
20
+ end
21
+ }
22
+ it{ should eq("(generator {allbut: Boolean})") }
23
+ end
24
+
25
+ end # nullary signature
26
+
27
+ describe "on a monadic operator" do
28
+ let(:clazz){ Operator::NonRelational::Coerce }
29
+
30
+ describe "on an empty signature" do
31
+ let(:signature){ Signature.new(clazz){|s|} }
32
+ it{ should eq("(coerce operand)") }
33
+ end
34
+
35
+ describe "on an option-only signature" do
36
+ let(:signature){
37
+ Signature.new(clazz) do |s|
38
+ s.option :allbut, Boolean
39
+ end
40
+ }
41
+ it{ should eq("(coerce operand, {allbut: Boolean})") }
42
+ end
43
+
44
+ describe "on an option-only signature with multiple options" do
45
+ let(:signature){
46
+ Signature.new(clazz) do |s|
47
+ s.option :allbut, Boolean
48
+ s.option :newname, AttrName
49
+ end
50
+ }
51
+ it{ should eq("(coerce operand, {allbut: Boolean, newname: AttrName})") }
52
+ end
53
+
54
+ describe "on a signature with one argument only" do
55
+ let(:signature){
56
+ Signature.new(clazz) do |s|
57
+ s.argument :by, AttrList
58
+ end
59
+ }
60
+ it{ should eq("(coerce operand, by:AttrList)") }
61
+ end
62
+
63
+ describe "on a signature with multiple arguments" do
64
+ let(:signature){
65
+ Signature.new(clazz) do |s|
66
+ s.argument :by, AttrList
67
+ s.argument :order, Ordering
68
+ end
69
+ }
70
+ it{ should eq("(coerce operand, by:AttrList, order:Ordering)") }
71
+ end
72
+
73
+ describe "on a full signature" do
74
+ let(:signature){
75
+ Signature.new(clazz) do |s|
76
+ s.argument :by, AttrList
77
+ s.argument :order, Ordering
78
+ s.option :allbut, Boolean
79
+ end
80
+ }
81
+ it{ should eq("(coerce operand, by:AttrList, order:Ordering, {allbut: Boolean})") }
82
+ end
83
+
84
+ end
85
+
86
+ describe "on a dyadic operator" do
87
+ let(:clazz){ Operator::Relational::Join }
88
+
89
+ describe "on an option-only signature" do
90
+ let(:signature){
91
+ Signature.new(clazz) do |s|
92
+ s.option :allbut, Boolean
93
+ end
94
+ }
95
+ it{ should eq("(join left, right, {allbut: Boolean})") }
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ module Operator
4
+ describe Signature, '#to_shell' do
5
+
6
+ subject{ signature.to_shell }
7
+
8
+ describe "on a nullary signature" do
9
+ let(:clazz){ Operator::NonRelational::Generator }
10
+
11
+ describe "on an empty signature" do
12
+ let(:signature){ Signature.new(clazz){|s|} }
13
+ it{ should eq("alf generator") }
14
+ end
15
+
16
+ describe "on an option-only signature" do
17
+ let(:signature){
18
+ Signature.new(clazz) do |s|
19
+ s.option :allbut, Boolean
20
+ end
21
+ }
22
+ it{ should eq("alf generator [--allbut]") }
23
+ end
24
+
25
+ end # nullary signature
26
+
27
+ describe "on a monadic operator" do
28
+ let(:clazz){ Operator::NonRelational::Coerce }
29
+
30
+ describe "on an empty signature" do
31
+ let(:signature){ Signature.new(clazz){|s|} }
32
+ it{ should eq("alf coerce [OPERAND]") }
33
+ end
34
+
35
+ describe "on an option-only signature" do
36
+ let(:signature){
37
+ Signature.new(clazz) do |s|
38
+ s.option :allbut, Boolean
39
+ end
40
+ }
41
+ it{ should eq("alf coerce [--allbut] [OPERAND]") }
42
+ end
43
+
44
+ describe "on an option-only signature with multiple options" do
45
+ let(:signature){
46
+ Signature.new(clazz) do |s|
47
+ s.option :allbut, Boolean
48
+ s.option :newname, AttrName
49
+ end
50
+ }
51
+ it{ should eq("alf coerce [--allbut] [--newname=NEWNAME] [OPERAND]") }
52
+ end
53
+
54
+ describe "on a signature with one argument only" do
55
+ let(:signature){
56
+ Signature.new(clazz) do |s|
57
+ s.argument :proj, AttrList
58
+ end
59
+ }
60
+ it{ should eq("alf coerce [OPERAND] -- PROJ") }
61
+ end
62
+
63
+ describe "on a signature with multiple arguments" do
64
+ let(:signature){
65
+ Signature.new(clazz) do |s|
66
+ s.argument :proj, AttrList
67
+ s.argument :ordering, Ordering
68
+ end
69
+ }
70
+ it{ should eq("alf coerce [OPERAND] -- PROJ -- ORDERING") }
71
+ end
72
+
73
+ describe "on a full signature" do
74
+ let(:signature){
75
+ Signature.new(clazz) do |s|
76
+ s.argument :proj, AttrList
77
+ s.argument :ordering, Ordering
78
+ s.option :allbut, Boolean
79
+ s.option :newname, AttrName
80
+ end
81
+ }
82
+ it{ should eq("alf coerce [--allbut] [--newname=NEWNAME] [OPERAND] -- PROJ -- ORDERING") }
83
+ end
84
+
85
+ end
86
+
87
+ describe "on a dyadic operator" do
88
+ let(:clazz){ Operator::Relational::Join }
89
+
90
+ describe "on an option-only signature" do
91
+ let(:signature){
92
+ Signature.new(clazz) do |s|
93
+ s.option :allbut, Boolean
94
+ end
95
+ }
96
+ it{ should eq("alf join [--allbut] [LEFT] RIGHT") }
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -8,11 +8,13 @@ module Alf
8
8
  x.sort{|m1,m2| m1.name.to_s <=> m2.name.to_s}.should == [
9
9
  Alf::Operator::NonRelational::Autonum,
10
10
  Alf::Operator::NonRelational::Clip,
11
+ Alf::Operator::NonRelational::Coerce,
11
12
  Alf::Operator::NonRelational::Compact,
12
13
  Alf::Operator::NonRelational::Defaults,
14
+ Alf::Operator::NonRelational::Generator,
13
15
  Alf::Operator::NonRelational::Sort,
14
16
  ]
15
17
  end
16
18
 
17
19
  end
18
- end
20
+ end
@@ -2,49 +2,54 @@ require 'spec_helper'
2
2
  module Alf
3
3
  describe Relation do
4
4
 
5
- let(:rel1){rel(
5
+ let(:rel1){Alf::Relation[
6
6
  {:sid => 'S1'},
7
7
  {:sid => 'S2'},
8
8
  {:sid => 'S3'}
9
- )}
9
+ ]}
10
10
 
11
- let(:rel2){rel(
11
+ let(:rel2){Alf::Relation[
12
12
  {:sid => 'S5'},
13
13
  {:sid => 'S2'}
14
- )}
14
+ ]}
15
15
 
16
+ specify "project" do
17
+ rel1.project([]).should eq(Alf::Relation[{}])
18
+ rel1.project([:sid], :allbut => true).should eq(Alf::Relation[{}])
19
+ end
20
+
16
21
  specify "allbut" do
17
- rel1.allbut([:sid]).should == rel({})
22
+ rel1.allbut([:sid]).should eq(Alf::Relation[{}])
18
23
  end
19
24
 
20
25
  specify "extend" do
21
- rel1.extend(:x => lambda{ sid.downcase }).should == rel(
26
+ rel1.extend(:x => lambda{ sid.downcase }).should == Alf::Relation[
22
27
  {:sid => 'S1', :x => 's1'},
23
28
  {:sid => 'S2', :x => 's2'},
24
29
  {:sid => 'S3', :x => 's3'}
25
- )
30
+ ]
26
31
  end
27
32
 
28
33
  specify "union" do
29
34
  (rel1 + rel1).should == rel1
30
- (rel1 + rel2).should == rel(
35
+ (rel1 + rel2).should == Alf::Relation[
31
36
  {:sid => 'S1'},
32
37
  {:sid => 'S3'},
33
38
  {:sid => 'S2'},
34
39
  {:sid => 'S5'}
35
- )
40
+ ]
36
41
  end # coerce
37
42
 
38
43
  specify "difference" do
39
- (rel1 - rel1).should == rel()
40
- (rel1 - rel2).should == rel(
44
+ (rel1 - rel1).should == Alf::Relation[]
45
+ (rel1 - rel2).should == Alf::Relation[
41
46
  {:sid => 'S1'},
42
47
  {:sid => 'S3'}
43
- )
44
- (rel2 - rel1).should == rel(
48
+ ]
49
+ (rel2 - rel1).should == Alf::Relation[
45
50
  {:sid => 'S5'}
46
- )
51
+ ]
47
52
  end # coerce
48
53
 
49
54
  end
50
- end
55
+ end
Binary file
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require "sequel"
4
+ module Alf
5
+ describe Sequel::Environment do
6
+
7
+ let(:rel) {Alf::Relation[
8
+ {:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
9
+ {:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
10
+ {:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'},
11
+ {:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'},
12
+ {:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'}
13
+ ]}
14
+
15
+ let(:file){ _("alf.db", __FILE__) }
16
+ let(:uri) { "sqlite://#{file}" }
17
+ let(:env) { Sequel::Environment.new(uri) }
18
+
19
+ before(:all){
20
+ unless File.exists?(file)
21
+ FileUtils.rm_rf file
22
+ db = ::Sequel.connect(uri)
23
+ db.create_table(:suppliers){
24
+ primary_key :sid
25
+ String :sid
26
+ String :name
27
+ Integer :status
28
+ String :city
29
+ }
30
+ rel.each{|tuple| db[:suppliers].insert(tuple)}
31
+ end
32
+ }
33
+
34
+ specify{
35
+ env.should be_a(Alf::Environment)
36
+ }
37
+
38
+ it "should serve iterators" do
39
+ env.dataset(:suppliers).should be_a(Alf::Iterator)
40
+ end
41
+
42
+ it "should be the correct relation" do
43
+ env.dataset(:suppliers).to_rel.should eq(rel)
44
+ end
45
+
46
+ specify ".recognizes?" do
47
+ Sequel::Environment.recognizes?([_("alf.db", __FILE__)]).should be_true
48
+ Sequel::Environment.recognizes?(["postgres://localhost/database"]).should be_true
49
+ Sequel::Environment.recognizes?(["nosuchone.db"]).should be_false
50
+ Sequel::Environment.recognizes?([nil]).should be_false
51
+ end
52
+
53
+ end
54
+ end
@@ -9,54 +9,64 @@ module Alf
9
9
  {:a => 1, :sign => -1},
10
10
  ]}
11
11
 
12
+ it "should keep track of registered aggregators" do
13
+ Aggregator.aggregators.should_not be_empty
14
+ Aggregator.each do |agg|
15
+ agg.should be_a(Class)
16
+ end
17
+ end
18
+
12
19
  it "should behave correctly on count" do
13
- Aggregator.count(:a).aggregate(input).should == 4
20
+ Aggregator.count{a}.aggregate(input).should == 4
14
21
  end
15
22
 
16
23
  it "should behave correctly on sum" do
17
- Aggregator.sum(:a).aggregate(input).should == 7
24
+ Aggregator.sum{a}.aggregate(input).should == 7
18
25
  end
19
26
 
20
27
  it "should behave correctly on avg" do
21
- Aggregator.avg(:a).aggregate(input).should == 7.0 / 4.0
28
+ Aggregator.avg{a}.aggregate(input).should == 7.0 / 4.0
22
29
  end
23
30
 
24
31
  it "should behave correctly on min" do
25
- Aggregator.min(:a).aggregate(input).should == 1
32
+ Aggregator.min{a}.aggregate(input).should == 1
26
33
  end
27
34
 
28
35
  it "should behave correctly on max" do
29
- Aggregator.max(:a).aggregate(input).should == 3
36
+ Aggregator.max{a}.aggregate(input).should == 3
30
37
  end
31
38
 
32
39
  it "should behave correctly on concat" do
33
- Aggregator.concat(:a).aggregate(input).should == "1231"
34
- Aggregator.concat(:a, :between => " ").aggregate(input).should == "1 2 3 1"
35
- Aggregator.concat(:a, :before => "[", :after => "]").aggregate(input).should == "[1231]"
40
+ Aggregator.concat{a}.aggregate(input).should == "1231"
41
+ Aggregator.concat(:between => " "){ a }.aggregate(input).should == "1 2 3 1"
36
42
  Aggregator.concat(:before => "[", :after => "]"){ a }.aggregate(input).should == "[1231]"
37
43
  end
38
44
 
39
45
  it "should behave correctly on collect" do
40
- Aggregator.collect(:a).aggregate(input).should == [1, 2, 3, 1]
46
+ Aggregator.collect{a}.aggregate(input).should == [1, 2, 3, 1]
41
47
  Aggregator.collect{ {:a => a, :sign => sign} }.aggregate(input).should == input
42
48
  end
43
49
 
44
- it "should behave correctly on group" do
45
- Aggregator.group(:a).aggregate(input).should == rel(
46
- {:a => 1},
47
- {:a => 2},
48
- {:a => 3}
49
- )
50
- Aggregator.group(:a, :sign).aggregate(input).should == rel(
51
- {:a => 1, :sign => -1},
52
- {:a => 2, :sign => 1 },
53
- {:a => 3, :sign => -1}
54
- )
55
- end
56
-
57
50
  it "should allow specific tuple computations" do
58
51
  Aggregator.sum{ 1.0 * a * sign }.aggregate(input).should == -3.0
59
52
  end
53
+
54
+ describe "coerce" do
55
+
56
+ subject{ Aggregator.coerce(arg) }
57
+
58
+ describe "from an Aggregator" do
59
+ let(:arg){ Aggregator.sum{a} }
60
+ it{ should eq(arg) }
61
+ end
62
+
63
+ describe "from a String" do
64
+ let(:arg){ "sum{a}" }
65
+ it{ should be_a(Aggregator::Sum) }
66
+ specify{ subject.aggregate(input).should eql(7) }
67
+ end
68
+
69
+ end
60
70
 
61
71
  end
62
72
  end
@@ -22,6 +22,11 @@ module Alf
22
22
  env.should be_a(Environment::Folder)
23
23
  end
24
24
 
25
+ it "should recognize a sqlite file" do
26
+ env = Environment.autodetect(_("sequel/alf.db", __FILE__))
27
+ env.should be_a(Sequel::Environment)
28
+ end
29
+
25
30
  it "should raise an Argument when no match" do
26
31
  lambda{ Environment.autodetect(12) }.should raise_error(ArgumentError)
27
32
  end
@@ -19,5 +19,9 @@ module Alf
19
19
  operator.to_a.should == expected
20
20
  end
21
21
 
22
+ it "should allow building aggregators" do
23
+ sum{ qty }.should be_a(Aggregator::Sum)
24
+ end
25
+
22
26
  end
23
27
  end
@@ -46,6 +46,11 @@ module Alf
46
46
  it_should_behave_like "A value"
47
47
  end
48
48
 
49
+ specify "different empty relations instances should be equal" do
50
+ Relation.new(Set.new).should eq(Relation.new(Set.new))
51
+ Relation[{}].should eq(Relation[{}])
52
+ end
53
+
49
54
  describe "DUM" do
50
55
  subject{ Relation::DUM }
51
56
  it_should_behave_like "A value"
@@ -9,22 +9,22 @@ module Alf
9
9
  Cell.new(100).text_rendering.should == "100"
10
10
  Cell.new(:hello).text_rendering.should == ":hello"
11
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"
12
+ Cell.new(10.0).text_rendering.should == "10.000"
13
+ Cell.new(10/3.0).text_rendering.should == "3.333"
14
14
  Cell.new([]).text_rendering.should == "[]"
15
- Cell.new([10/3.0, true]).text_rendering.should == "[3.3333333, true]"
15
+ Cell.new([10/3.0, true]).text_rendering.should == "[3.333, true]"
16
16
  end
17
17
 
18
18
  specify "min_width" do
19
19
  Cell.new("").min_width.should == 0
20
- Cell.new(10/3.0).min_width.should == 9
20
+ Cell.new(10/3.0).min_width.should == 5
21
21
  Cell.new("12\n5345").min_width.should == 4
22
22
  end
23
23
 
24
24
  specify "rendering_lines" do
25
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]"]
26
+ Cell.new(10/3.0).rendering_lines.should == ["3.333"]
27
+ Cell.new([10/3.0,true]).rendering_lines.should == ["[3.333, true]"]
28
28
  Cell.new("abc").rendering_lines(5).should == ["abc "]
29
29
  Cell.new(12).rendering_lines(5).should == [" 12"]
30
30
  end
@@ -9,8 +9,8 @@ module Alf
9
9
 
10
10
  let(:values){ [ 10/3.0, true ] }
11
11
  specify "rendering_lines" do
12
- row.rendering_lines.should == ["| 3.3333333 | true |"]
13
- row.rendering_lines([10,5]).should == ["| 3.3333333 | true |"]
12
+ row.rendering_lines.should == ["| 3.333 | true |"]
13
+ row.rendering_lines([10,5]).should == ["| 3.333 | true |"]
14
14
  end
15
15
 
16
16
  end
@@ -20,7 +20,7 @@ module Alf
20
20
  let(:values){ [ 10/3.0, [1, 2, 3] ] }
21
21
 
22
22
  specify "rendering_lines" do
23
- row.rendering_lines.should == ["| 3.3333333 | [1, 2, 3] |"]
23
+ row.rendering_lines.should == ["| 3.333 | [1, 2, 3] |"]
24
24
  end
25
25
 
26
26
  end
@@ -24,12 +24,12 @@ module Alf
24
24
  let(:records){ [ [:by_x, 10.0], [:by_y, 2.0] ] }
25
25
 
26
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"
27
+ table.render.should == "+---------+--------+\n" +
28
+ "| :method | :total |\n" +
29
+ "+---------+--------+\n" +
30
+ "| :by_x | 10.000 |\n" +
31
+ "| :by_y | 2.000 |\n" +
32
+ "+---------+--------+\n"
33
33
  end
34
34
 
35
35
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe "Tools#coalesce" do
4
+
5
+ it "should support a varargs variant" do
6
+ Tools.coalesce(:a, nil, :b, :c).should eql(:a)
7
+ Tools.coalesce(nil, :a, nil, :b, :c).should eql(:a)
8
+ end
9
+
10
+ it "should support a block for costly computations" do
11
+ Tools.coalesce(nil){ :hello }.should eql(:hello)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ module Alf
3
+ describe "Tools#coerce" do
4
+
5
+ specify {
6
+ Tools.coerce("12", Integer).should eql(12)
7
+ }
8
+
9
+ end
10
+ end