alf 0.9.3 → 0.10.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 (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