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,157 @@
1
+ module Alf
2
+ module Lispy
3
+
4
+ alias :ruby_extend :extend
5
+
6
+ # The environment
7
+ attr_accessor :environment
8
+
9
+ #
10
+ # Compiles a query expression given by a String or a block and returns
11
+ # the result (typically a tuple iterator)
12
+ #
13
+ # Example
14
+ #
15
+ # # with a string
16
+ # op = compile "(restrict :suppliers, lambda{ city == 'London' })"
17
+ #
18
+ # # or with a block
19
+ # op = compile {
20
+ # (restrict :suppliers, lambda{ city == 'London' })
21
+ # }
22
+ #
23
+ # @param [String] expr a Lispy expression to compile
24
+ # @return [Iterator] the iterator resulting from compilation
25
+ #
26
+ def compile(expr = nil, path = nil, &block)
27
+ if expr.nil?
28
+ instance_eval(&block)
29
+ else
30
+ b = _clean_binding
31
+ (path ? Kernel.eval(expr, b, path) : Kernel.eval(expr, b))
32
+ end
33
+ end
34
+
35
+ #
36
+ # Evaluates a query expression given by a String or a block and returns
37
+ # the result as an in-memory relation (Alf::Relation)
38
+ #
39
+ # Example:
40
+ #
41
+ # # with a string
42
+ # rel = evaluate "(restrict :suppliers, lambda{ city == 'London' })"
43
+ #
44
+ # # or with a block
45
+ # rel = evaluate {
46
+ # (restrict :suppliers, lambda{ city == 'London' })
47
+ # }
48
+ #
49
+ def evaluate(expr = nil, path = nil, &block)
50
+ compiled = compile(expr, path, &block)
51
+ case compiled
52
+ when Iterator
53
+ compiled.to_rel
54
+ else
55
+ compiled
56
+ end
57
+ end
58
+
59
+ #
60
+ # Coerces `h` to a valid tuple.
61
+ #
62
+ # @param [Hash] h, a hash mapping symbols to values
63
+ #
64
+ def Tuple(h)
65
+ unless h.keys.all?{|k| k.is_a?(Symbol)} &&
66
+ h.values.all?{|v| !v.nil?}
67
+ raise ArgumentError, "Invalid tuple literal #{h.inspect}"
68
+ end
69
+ h
70
+ end
71
+
72
+ #
73
+ # Coerces `args` to a valid relation.
74
+ #
75
+ def Relation(first, *args)
76
+ if args.empty?
77
+ if first.is_a?(Symbol)
78
+ environment.dataset(first).to_rel
79
+ elsif first.is_a?(Hash)
80
+ Alf::Relation[first]
81
+ else
82
+ raise ArgumentError, "Unable to coerce `#{first.inspect}` to a relation"
83
+ end
84
+ else
85
+ Alf::Relation[*args.unshift(first)]
86
+ end
87
+ end
88
+
89
+ #
90
+ # Install the DSL through iteration over defined operators
91
+ #
92
+ Operator.each do |op_class|
93
+ meth_name = Tools.ruby_case(Tools.class_name(op_class)).to_sym
94
+ if op_class.unary?
95
+ define_method(meth_name) do |child, *args|
96
+ child = Iterator.coerce(child, environment)
97
+ op_class.new(*args).pipe(child, environment)
98
+ end
99
+ elsif op_class.binary?
100
+ define_method(meth_name) do |left, right, *args|
101
+ operands = [left, right].collect{|x| Iterator.coerce(x, environment)}
102
+ op_class.new(*args).pipe(operands, environment)
103
+ end
104
+ elsif op_class.nullary?
105
+ define_method(meth_name) do |*args|
106
+ op_class.new(*args).pipe(nil, environment)
107
+ end
108
+ else
109
+ raise "Unexpected operator #{op_class}"
110
+ end
111
+ end # Operators::each
112
+
113
+ #
114
+ # Install the DSL through iteration over defined aggregators
115
+ #
116
+ Aggregator.each do |agg_class|
117
+ agg_name = Tools.ruby_case(Tools.class_name(agg_class)).to_sym
118
+ if method_defined?(agg_name)
119
+ raise "Unexpected method clash on Lispy: #{agg_name}"
120
+ else
121
+ define_method(agg_name) do |*args, &block|
122
+ agg_class.new(*args, &block)
123
+ end
124
+ end
125
+ end
126
+
127
+ def allbut(child, attributes)
128
+ (project child, attributes, :allbut => true)
129
+ end
130
+
131
+ #
132
+ # Runs a command as in shell.
133
+ #
134
+ # Example:
135
+ #
136
+ # lispy = Alf.lispy(Alf::Environment.examples)
137
+ # op = lispy.run(['restrict', 'suppliers', '--', "city == 'Paris'"])
138
+ #
139
+ def run(argv, requester = nil)
140
+ argv = Quickl.parse_commandline_args(argv) if argv.is_a?(String)
141
+ argv = Quickl.split_commandline_args(argv, '|')
142
+ argv.inject(nil) do |cmd,arr|
143
+ arr.shift if arr.first == "alf"
144
+ main = Alf::Command::Main.new(environment)
145
+ main.stdin_reader = cmd unless cmd.nil?
146
+ main.run(arr, requester)
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def _clean_binding
153
+ binding
154
+ end
155
+
156
+ end # module Lispy
157
+ end # module Alf
@@ -0,0 +1,74 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Contains all methods for operator instances
5
+ #
6
+ module Base
7
+
8
+ #
9
+ # Input datasets
10
+ #
11
+ attr_accessor :datasets
12
+
13
+ #
14
+ # Optional environment
15
+ #
16
+ attr_accessor :environment
17
+
18
+ #
19
+ # Create an operator instance
20
+ #
21
+ def initialize(*args)
22
+ signature.parse_args(args, self)
23
+ end
24
+
25
+ #
26
+ # Sets the operator input
27
+ #
28
+ def pipe(input, env = environment)
29
+ raise NotImplementedError, "Operator#pipe should be overriden"
30
+ end
31
+
32
+ #
33
+ # Returns operator signature.
34
+ #
35
+ def signature
36
+ self.class.signature
37
+ end
38
+
39
+ #
40
+ # Yields each tuple in turn
41
+ #
42
+ # This method is implemented in a way that ensures that all operators are
43
+ # thread safe. It is not intended to be overriden, use _each instead.
44
+ #
45
+ def each
46
+ op = self.dup
47
+ op._prepare
48
+ op._each(&Proc.new)
49
+ end
50
+
51
+ protected
52
+
53
+ #
54
+ # Prepares the iterator before subsequent call to _each.
55
+ #
56
+ # This method is intended to be overriden by suclasses to install what's
57
+ # need for successful iteration. The default implementation does nothing.
58
+ #
59
+ def _prepare
60
+ end
61
+
62
+ # Internal implementation of the iterator.
63
+ #
64
+ # This method must be implemented by subclasses. It is safe to use instance
65
+ # variables (typically initialized in _prepare) here.
66
+ #
67
+ def _each
68
+ end
69
+
70
+ private :datasets=, :environment=
71
+ end # module Base
72
+ include Base
73
+ end # module Operator
74
+ end # module Alf
@@ -0,0 +1,32 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Specialization of Operator for operators that work on a binary input
5
+ #
6
+ module Binary
7
+ include Operator
8
+
9
+ #
10
+ # Sets the operator input
11
+ #
12
+ def pipe(input, env = environment)
13
+ self.environment = env
14
+ self.datasets = input
15
+ self
16
+ end
17
+
18
+ protected
19
+
20
+ # Returns the left operand
21
+ def left
22
+ Iterator.coerce(datasets.first, environment)
23
+ end
24
+
25
+ # Returns the right operand
26
+ def right
27
+ Iterator.coerce(datasets.last, environment)
28
+ end
29
+
30
+ end # module Binary
31
+ end # module Operator
32
+ end # module Alf
@@ -0,0 +1,45 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Specialization of Operator for implementing operators that rely on a
5
+ # cesure algorithm.
6
+ #
7
+ module Cesure
8
+ include Unary
9
+
10
+ protected
11
+
12
+ # (see Operator#_each)
13
+ def _each
14
+ receiver, prev_key = Proc.new, nil
15
+ each_input_tuple do |tuple|
16
+ cur_key = project(tuple)
17
+ if cur_key != prev_key
18
+ flush_cesure(prev_key, receiver) unless prev_key.nil?
19
+ start_cesure(cur_key, receiver)
20
+ prev_key = cur_key
21
+ end
22
+ accumulate_cesure(tuple, receiver)
23
+ end
24
+ flush_cesure(prev_key, receiver) unless prev_key.nil?
25
+ end
26
+
27
+ # Projects a given tuple and returns it's cesure projection
28
+ def project(tuple)
29
+ end
30
+
31
+ # Callback fired every time a new block starts
32
+ def start_cesure(key, receiver)
33
+ end
34
+
35
+ # Callback fired on each tuple of the current block
36
+ def accumulate_cesure(tuple, receiver)
37
+ end
38
+
39
+ # Callback fired at end of a block
40
+ def flush_cesure(key, receiver)
41
+ end
42
+
43
+ end # module Cesure
44
+ end # module Operator
45
+ end # module Alf
@@ -0,0 +1,132 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Encapsulates method that allows making operator introspection, that is,
5
+ # knowing operator cardinality and similar stuff.
6
+ #
7
+ module ClassMethods
8
+
9
+ #
10
+ # Returns false
11
+ #
12
+ def command?
13
+ false
14
+ end
15
+
16
+ #
17
+ # Returns true
18
+ #
19
+ def operator?
20
+ true
21
+ end
22
+
23
+ #
24
+ # Returns true if this is a relational operator, false otherwise
25
+ #
26
+ def relational?
27
+ ancestors.include?(Relational)
28
+ end
29
+
30
+ #
31
+ # Returns true if this is a non relational operator, false otherwise
32
+ #
33
+ def non_relational?
34
+ ancestors.include?(NonRelational)
35
+ end
36
+
37
+ #
38
+ # Runs the command on commandline arguments
39
+ #
40
+ # @param [Array] argv an array of commandline arguments, typically ARGV
41
+ # @param [Object] req an optional requester, typically a super command
42
+ # @return [Iterator] an Iterator with query result
43
+ #
44
+ def run(argv, req = nil)
45
+ inst, operands = from_argv(argv)
46
+
47
+ # find standard input reader
48
+ stdin_reader = if req && req.respond_to?(:stdin_reader)
49
+ req.stdin_reader
50
+ else
51
+ Reader.coerce($stdin)
52
+ end
53
+
54
+ # normalize operands
55
+ operands = [ stdin_reader ] + Array(operands)
56
+ operands = operands.collect{|op|
57
+ Iterator.coerce(op, req && req.environment)
58
+ }
59
+ operands = if nullary?
60
+ []
61
+ elsif unary?
62
+ operands.last
63
+ elsif binary?
64
+ operands[-2..-1]
65
+ end
66
+
67
+ inst.pipe(operands, req && req.environment)
68
+ inst
69
+ end
70
+
71
+ #
72
+ # Returns true if this operator is a zero-ary operator, false otherwise
73
+ #
74
+ def nullary?
75
+ ancestors.include?(Operator::Nullary)
76
+ end
77
+
78
+ #
79
+ # Returns true if this operator is an unary operator, false otherwise
80
+ #
81
+ def unary?
82
+ ancestors.include?(Operator::Unary)
83
+ end
84
+
85
+ #
86
+ # Returns true if this operator is a binary operator, false otherwise
87
+ #
88
+ def binary?
89
+ ancestors.include?(Operator::Binary)
90
+ end
91
+
92
+ #
93
+ # Installs or set the operator signature
94
+ #
95
+ def signature
96
+ if block_given?
97
+ @signature = Signature.new(self, &Proc.new)
98
+ @signature.install
99
+ options do |opt|
100
+ signature.fill_option_parser(opt, self)
101
+ end
102
+ else
103
+ @signature ||= Signature.new(self)
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ # Factors an operator instance from commandline arguments
110
+ def from_argv(argv)
111
+ inst = new
112
+ operands = inst.signature.parse_argv(argv, inst)
113
+ [inst, operands]
114
+ end
115
+
116
+ end # module ClassMethods
117
+
118
+ #
119
+ # Yields non-relational then relational operators, in turn.
120
+ #
121
+ def self.each
122
+ Operator::NonRelational.each{|x| yield(x)}
123
+ Operator::Relational.each{|x| yield(x)}
124
+ end
125
+
126
+ # Ensures that the Introspection module is set on real operators
127
+ def self.included(mod)
128
+ mod.extend(ClassMethods) if mod.is_a?(Class)
129
+ end
130
+
131
+ end # module Operator
132
+ end # module Alf
@@ -0,0 +1,9 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Marker for experimental operators
5
+ #
6
+ module Experimental
7
+ end # module Experimental
8
+ end # module Operator
9
+ end # module Alf
@@ -0,0 +1,24 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Autonum < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Transform
5
+
6
+ signature do |s|
7
+ s.argument :as, AttrName, :autonum
8
+ end
9
+
10
+ protected
11
+
12
+ # (see Operator#_prepare)
13
+ def _prepare
14
+ @autonum = -1
15
+ end
16
+
17
+ # (see Operator::Transform#_tuple2tuple)
18
+ def _tuple2tuple(tuple)
19
+ tuple.merge(@as => (@autonum += 1))
20
+ end
21
+
22
+ end # class Autonum
23
+ end # module Operator::NonRelational
24
+ end # module Alf
@@ -0,0 +1,20 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Clip < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Transform
5
+
6
+ signature do |s|
7
+ s.argument :attributes, AttrList, []
8
+ s.option :allbut, Boolean, false, "Apply an allbut clipping?"
9
+ end
10
+
11
+ protected
12
+
13
+ # (see Operator::Transform#_tuple2tuple)
14
+ def _tuple2tuple(tuple)
15
+ @attributes.project(tuple, @allbut)
16
+ end
17
+
18
+ end # class Clip
19
+ end # module Operator::NonRelational
20
+ end # module Alf
@@ -0,0 +1,21 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Coerce < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Transform
5
+
6
+ signature do |s|
7
+ s.argument :heading, Heading, {}
8
+ end
9
+
10
+ protected
11
+
12
+ # (see Operator::Transform#_tuple2tuple)
13
+ def _tuple2tuple(tuple)
14
+ tuple.merge tuple_collect(@heading.attributes){|k,d|
15
+ [k, coerce(tuple[k], d)]
16
+ }
17
+ end
18
+
19
+ end # class Coerce
20
+ end # module Operator::NonRelational
21
+ end # module Alf
@@ -0,0 +1,62 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Compact < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Shortcut, Operator::Unary
5
+
6
+ signature do |s|
7
+ end
8
+
9
+ # Removes duplicates according to a complete order
10
+ class SortBased
11
+ include Operator, Operator::Cesure
12
+
13
+ def initialize
14
+ @cesure_key ||= AttrList.new([])
15
+ end
16
+
17
+ protected
18
+
19
+ # (see Operator::Cesure#project)
20
+ def project(tuple)
21
+ @cesure_key.project(tuple, true)
22
+ end
23
+
24
+ # (see Operator::Cesure#accumulate_cesure)
25
+ def accumulate_cesure(tuple, receiver)
26
+ @tuple = tuple
27
+ end
28
+
29
+ # (see Operator::Cesure#flush_cesure)
30
+ def flush_cesure(key, receiver)
31
+ receiver.call(@tuple)
32
+ end
33
+
34
+ end # class SortBased
35
+
36
+ # Removes duplicates by loading all in memory and filtering
37
+ # them there
38
+ class BufferBased
39
+ include Operator, Operator::Unary
40
+
41
+ protected
42
+
43
+ def _prepare
44
+ @tuples = input.to_a.uniq
45
+ end
46
+
47
+ def _each
48
+ @tuples.each(&Proc.new)
49
+ end
50
+
51
+ end # class BufferBased
52
+
53
+ protected
54
+
55
+ def longexpr
56
+ chain BufferBased.new,
57
+ datasets
58
+ end
59
+
60
+ end # class Compact
61
+ end # module Operator::NonRelational
62
+ end # module Alf
@@ -0,0 +1,25 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Defaults < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Transform
5
+
6
+ signature do |s|
7
+ s.argument :defaults, TupleComputation, {}
8
+ s.option :strict, Boolean, false, "Restrict to default attributes only?"
9
+ end
10
+
11
+ protected
12
+
13
+ # (see Operator::Transform#_tuple2tuple)
14
+ def _tuple2tuple(tuple)
15
+ handle = TupleHandle.new.set(tuple)
16
+ defs = @defaults.evaluate(handle)
17
+ keys = @strict ? defs.keys : (tuple.keys | defs.keys)
18
+ tuple_collect(keys){|k|
19
+ [k, coalesce(tuple[k], defs[k])]
20
+ }
21
+ end
22
+
23
+ end # class Defaults
24
+ end # module Operator::NonRelational
25
+ end # module Alf
@@ -0,0 +1,38 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Generator < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Nullary
5
+
6
+ class Size < Integer
7
+ extend Myrrha::Domain
8
+
9
+ def self.coerce(args)
10
+ Tools.coerce(args, Integer)
11
+ end
12
+
13
+ def self.from_argv(argv, opts = {})
14
+ coerce(argv.first)
15
+ end
16
+
17
+ def self.predicate
18
+ @predicate ||= lambda{|i| i >= 0}
19
+ end
20
+
21
+ end # Size
22
+
23
+ signature do |s|
24
+ s.argument :size, Size, 10
25
+ s.argument :as, AttrName, :num
26
+ end
27
+
28
+ protected
29
+
30
+ def _each
31
+ size.times do |i|
32
+ yield(@as => i+1)
33
+ end
34
+ end
35
+
36
+ end # class Generator
37
+ end # module Operator::NonRelational
38
+ end # module Alf
@@ -0,0 +1,23 @@
1
+ module Alf
2
+ module Operator::NonRelational
3
+ class Sort < Alf::Operator()
4
+ include Operator::NonRelational, Operator::Unary
5
+
6
+ signature do |s|
7
+ s.argument :ordering, Ordering, []
8
+ end
9
+
10
+ protected
11
+
12
+ def _prepare
13
+ @buffer = Buffer::Sorted.new(ordering)
14
+ @buffer.add_all(input)
15
+ end
16
+
17
+ def _each
18
+ @buffer.each(&Proc.new)
19
+ end
20
+
21
+ end # class Sort
22
+ end # module Operator::NonRelational
23
+ end # module Alf
@@ -0,0 +1,20 @@
1
+ module Alf
2
+ module Operator
3
+ #
4
+ # Specialization of Operator for operators without operands
5
+ #
6
+ module Nullary
7
+ include Operator
8
+
9
+ #
10
+ # Sets the operator input
11
+ #
12
+ def pipe(input, env = environment)
13
+ self.environment = env
14
+ self.datasets = []
15
+ self
16
+ end
17
+
18
+ end # module Nullary
19
+ end # module Operator
20
+ end # module Alf