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,96 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Defines a Heading, that is, a set of attribute (name,domain) pairs.
5
+ #
6
+ class Heading
7
+
8
+ #
9
+ # Creates a Heading instance
10
+ #
11
+ # @param [Hash] a hash of attribute (name, type) pairs where name is
12
+ # a Symbol and type is a Class
13
+ #
14
+ def self.[](attributes)
15
+ Heading.new(attributes)
16
+ end
17
+
18
+ # @return [Hash] a (freezed) hash of (name, type) pairs
19
+ attr_reader :attributes
20
+
21
+ #
22
+ # Creates a Heading instance
23
+ #
24
+ # @param [Hash] a hash of attribute (name, type) pairs where name is
25
+ # a Symbol and type is a Class
26
+ #
27
+ def initialize(attributes)
28
+ @attributes = attributes.dup.freeze
29
+ end
30
+
31
+ #
32
+ # Coerces `attributes` to a Heading instance
33
+ #
34
+ def self.coerce(attributes)
35
+ case attributes
36
+ when Array
37
+ h = Tools.tuple_collect(attributes.each_slice(2)) do |k,v|
38
+ [ Tools.coerce(k, Symbol), Tools.coerce(v, Module) ]
39
+ end
40
+ Heading.new(h)
41
+ when Hash
42
+ Heading.new(attributes)
43
+ else
44
+ raise ArgumentError, "Unable to coerce #{attributes.inspect} to a Heading"
45
+ end
46
+ end
47
+
48
+ def self.from_argv(argv, opts = {})
49
+ coerce(argv)
50
+ end
51
+
52
+ #
53
+ # Returns heading's cardinality
54
+ #
55
+ def cardinality
56
+ attributes.size
57
+ end
58
+ alias :size :cardinality
59
+ alias :count :cardinality
60
+
61
+ #
62
+ # Returns heading's hash code
63
+ #
64
+ def hash
65
+ @hash ||= attributes.hash
66
+ end
67
+
68
+ #
69
+ # Checks equality with other heading
70
+ #
71
+ def ==(other)
72
+ other.is_a?(Heading) && (other.attributes == attributes)
73
+ end
74
+ alias :eql? :==
75
+
76
+ #
77
+ # Converts this heading to a Hash of (name,type) pairs
78
+ #
79
+ def to_hash
80
+ attributes.dup
81
+ end
82
+
83
+ #
84
+ # Returns a Heading literal
85
+ #
86
+ def to_ruby_literal
87
+ attributes.empty? ?
88
+ "Alf::Heading::EMPTY" :
89
+ "Alf::Heading[#{Tools.to_ruby_literal(attributes)[1...-1]}]"
90
+ end
91
+ alias :inspect :to_ruby_literal
92
+
93
+ EMPTY = Heading.new({})
94
+ end # class Heading
95
+ end # module Types
96
+ end # module Alf
@@ -0,0 +1,93 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Encapsulates tools for computing orders on tuples
5
+ #
6
+ class Ordering
7
+
8
+ attr_reader :ordering
9
+
10
+ def initialize(ordering = [])
11
+ @ordering = ordering
12
+ @sorter = nil
13
+ end
14
+
15
+ #
16
+ # Coerces `arg` to an ordering key.
17
+ #
18
+ # Implemented coercions are:
19
+ # * Array of symbols (all attributes in ascending order)
20
+ # * Array of [Symbol, :asc|:desc] pairs (obvious semantics)
21
+ # * AttrList (all its attributes in ascending order)
22
+ # * Ordering (self)
23
+ #
24
+ # @return [Ordering]
25
+ # @raises [ArgumentError] when `arg` is not recognized
26
+ #
27
+ def self.coerce(arg)
28
+ case arg
29
+ when Ordering
30
+ arg
31
+ when AttrList
32
+ arg.to_ordering
33
+ when Array
34
+ if arg.all?{|a| a.is_a?(Array)}
35
+ Ordering.new(arg)
36
+ else
37
+ symbolized = arg.collect{|s| Tools.coerce(s, Symbol)}
38
+ sliced = symbolized.each_slice(2)
39
+ if sliced.all?{|a,o| [:asc,:desc].include?(o)}
40
+ Ordering.new sliced.to_a
41
+ else
42
+ Ordering.new symbolized.collect{|a| [a, :asc]}
43
+ end
44
+ end
45
+ else
46
+ raise ArgumentError, "Unable to coerce #{arg} to an ordering key"
47
+ end
48
+ end
49
+
50
+ def self.from_argv(argv, opts = {})
51
+ coerce(argv)
52
+ end
53
+
54
+ def attributes
55
+ @ordering.collect{|arg| arg.first}
56
+ end
57
+
58
+ def order_by(attr, order = :asc)
59
+ @ordering << [attr, order]
60
+ @sorter = nil
61
+ self
62
+ end
63
+
64
+ def order_of(attr)
65
+ @ordering.find{|arg| arg.first == attr}.last
66
+ end
67
+
68
+ def compare(t1,t2)
69
+ @ordering.each do |attr,order|
70
+ x, y = t1[attr], t2[attr]
71
+ comp = x.respond_to?(:<=>) ? (x <=> y) : (x.to_s <=> y.to_s)
72
+ comp *= -1 if order == :desc
73
+ return comp unless comp == 0
74
+ end
75
+ return 0
76
+ end
77
+
78
+ def sorter
79
+ @sorter ||= lambda{|t1,t2| compare(t1, t2)}
80
+ end
81
+
82
+ def +(other)
83
+ other = Ordering.coerce(other)
84
+ Ordering.new(@ordering + other.ordering)
85
+ end
86
+
87
+ def ==(other)
88
+ other.is_a?(Ordering) && (other.ordering == ordering)
89
+ end
90
+
91
+ end # class Ordering
92
+ end # module Types
93
+ end # module Alf
@@ -0,0 +1,57 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Encapsulates a Renaming information
5
+ #
6
+ class Renaming
7
+
8
+ # @return [Hash] a renaming mapping as AttrName -> AttrName
9
+ attr_reader :renaming
10
+
11
+ #
12
+ # Creates a renaming instance
13
+ #
14
+ # @param [Hash] a renaming mapping as AttrName -> AttrName
15
+ #
16
+ def initialize(renaming)
17
+ @renaming = renaming
18
+ end
19
+
20
+ #
21
+ # Coerces `arg` to a renaming
22
+ #
23
+ def self.coerce(arg)
24
+ case arg
25
+ when Renaming
26
+ arg
27
+ when Hash
28
+ h = Tools.tuple_collect(arg){|k,v|
29
+ [Tools.coerce(k, AttrName), Tools.coerce(v, AttrName)]
30
+ }
31
+ Renaming.new(h)
32
+ when Array
33
+ coerce(Hash[*arg])
34
+ else
35
+ raise ArgumentError, "Invalid argument `#{arg}` for Renaming()"
36
+ end
37
+ end
38
+
39
+ def self.from_argv(argv, opts = {})
40
+ coerce(argv)
41
+ end
42
+
43
+ #
44
+ # Applies renaming to a a given tuple
45
+ #
46
+ def apply(tuple)
47
+ Tools.tuple_collect(tuple){|k,v| [@renaming[k] || k, v]}
48
+ end
49
+
50
+ # Checks if this renaming is equal to `other`
51
+ def ==(other)
52
+ other.is_a?(Renaming) && (other.renaming == renaming)
53
+ end
54
+
55
+ end # class Renaming
56
+ end # module Types
57
+ end # module Alf
@@ -0,0 +1,76 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Encapsulates a Summarization information
5
+ #
6
+ class Summarization
7
+
8
+ # @return [Hash] the hash of aggregations, AttrName -> Aggregators
9
+ attr_reader :aggregations
10
+
11
+ #
12
+ # Creates a Summarization instance
13
+ #
14
+ # @param [Hash] aggs, aggregations as a mapping AttrName -> Aggregators
15
+ #
16
+ def initialize(aggs)
17
+ @aggregations = aggs
18
+ end
19
+
20
+ #
21
+ # Coerces `arg` to an Aggregator
22
+ #
23
+ def self.coerce(arg)
24
+ case arg
25
+ when Summarization
26
+ arg
27
+ when Array
28
+ coerce(Hash[*arg])
29
+ when Hash
30
+ h = Tools.tuple_collect(arg) do |k,v|
31
+ [Tools.coerce(k, AttrName), Tools.coerce(v, Aggregator)]
32
+ end
33
+ Summarization.new(h)
34
+ else
35
+ raise ArgumentError, "Invalid arg `#{arg}` for Summarization()"
36
+ end
37
+ end
38
+
39
+ def self.from_argv(argv, opts = {})
40
+ coerce(argv)
41
+ end
42
+
43
+ #
44
+ # Computes the least tuple
45
+ #
46
+ def least
47
+ Tools.tuple_collect(@aggregations){|k,v|
48
+ [k, v.least]
49
+ }
50
+ end
51
+
52
+ #
53
+ # Computes the resulting aggregation from aggs if tuple happens.
54
+ #
55
+ def happens(aggs, tuple)
56
+ Tools.tuple_collect(@aggregations){|k,v|
57
+ [k, v.happens(aggs[k], tuple)]
58
+ }
59
+ end
60
+
61
+ #
62
+ # Finalizes the summarization `aggs`
63
+ #
64
+ def finalize(aggs)
65
+ Tools.tuple_collect(@aggregations){|k,v|
66
+ [k, v.finalize(aggs[k])]
67
+ }
68
+ end
69
+
70
+ def ==(other)
71
+ other.is_a?(Summarization) && (other.aggregations == aggregations)
72
+ end
73
+
74
+ end # class Summarization
75
+ end # module Types
76
+ end # module Alf
@@ -0,0 +1,61 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Encapsulates a tuple computation from other tuples expressions
5
+ #
6
+ class TupleComputation
7
+
8
+ # @return [Hash] a computation hash, mapping AttrName -> TupleExpression
9
+ attr_reader :computation
10
+
11
+ #
12
+ # Creates a TupleComputation instance
13
+ #
14
+ # @param [Hash] computation, a mappping AttrName -> TupleExpression
15
+ #
16
+ def initialize(computation)
17
+ @computation = computation
18
+ end
19
+
20
+ #
21
+ # Coerces `arg` to a tuple computation
22
+ #
23
+ def self.coerce(arg)
24
+ case arg
25
+ when TupleComputation
26
+ arg
27
+ when Hash
28
+ h = Tools.tuple_collect(arg){|k,v|
29
+ if AttrName === k
30
+ v = TupleExpression.coerce(v) if v.is_a?(Proc)
31
+ [k, v]
32
+ else
33
+ [Tools.coerce(k, AttrName), Tools.coerce(v, TupleExpression)]
34
+ end
35
+ }
36
+ TupleComputation.new(h)
37
+ when Array
38
+ coerce(Hash[*arg])
39
+ else
40
+ raise ArgumentError, "Invalid argument `arg` for TupleComputation()"
41
+ end
42
+ end
43
+
44
+ # Coerce from ARGV
45
+ def self.from_argv(argv, opts = {})
46
+ coerce(argv)
47
+ end
48
+
49
+ #
50
+ # Computes the result, given `tuple` as context and `handle` to
51
+ # evaluate expressions.
52
+ #
53
+ def evaluate(obj = nil)
54
+ Tools.tuple_collect(@computation){|k,v|
55
+ [k, v.is_a?(TupleExpression) ? v.evaluate(obj) : v]
56
+ }
57
+ end
58
+
59
+ end # class TupleComputation
60
+ end # module Types
61
+ end # module Alf
@@ -0,0 +1,61 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Encapsulates the notion of tuple expression, which is a Ruby expression
5
+ # whose evaluates in the context and scope of a specific tuple.
6
+ #
7
+ class TupleExpression
8
+
9
+ # @return [Proc] the lambda expression
10
+ attr_reader :expr_lambda
11
+
12
+ # @return [String] the expression source code
13
+ attr_reader :source
14
+
15
+ #
16
+ # Creates a tuple expression from a Proc object
17
+ #
18
+ # @param [Proc] expr a Proc for the expression
19
+ #
20
+ def initialize(expr, source = nil)
21
+ @expr_lambda = expr
22
+ @source = source
23
+ end
24
+
25
+ #
26
+ # Coerces `arg` to a tuple expression
27
+ #
28
+ def self.coerce(arg)
29
+ case arg
30
+ when TupleExpression
31
+ arg
32
+ when Proc
33
+ TupleExpression.new(arg, nil)
34
+ when String, Symbol
35
+ lamb = eval("lambda{ #{arg} }")
36
+ TupleExpression.new(lamb, arg.to_s)
37
+ else
38
+ raise ArgumentError, "Invalid argument `#{arg}` for TupleExpression()"
39
+ end
40
+ end
41
+
42
+ # Coerces from ARGV
43
+ def self.from_argv(argv, options = {})
44
+ raise ArgumentError if argv.size > 1
45
+ coerce(argv.first || options[:default])
46
+ end
47
+
48
+ #
49
+ # Evaluates in the context of obj
50
+ #
51
+ def evaluate(obj = nil)
52
+ if RUBY_VERSION < "1.9"
53
+ obj.instance_eval(&@expr_lambda)
54
+ else
55
+ obj.instance_exec(&@expr_lambda)
56
+ end
57
+ end
58
+
59
+ end # class TupleExpression
60
+ end # module Types
61
+ end # module Alf
@@ -0,0 +1,49 @@
1
+ module Alf
2
+ module Types
3
+ #
4
+ # Specialization of TupleExpression to boolean expressions
5
+ # specifically
6
+ #
7
+ class TuplePredicate < TupleExpression
8
+
9
+ #
10
+ # Coerces `arg` to a TuplePredicate
11
+ #
12
+ def self.coerce(arg)
13
+ case arg
14
+ when TuplePredicate
15
+ arg
16
+ when TupleExpression
17
+ TuplePredicate.new arg.expr_lambda, arg.source
18
+ when TrueClass, FalseClass
19
+ TuplePredicate.new lambda{ arg }, arg.to_s
20
+ when Proc
21
+ TuplePredicate.new arg, nil
22
+ when String, Symbol
23
+ l = eval("lambda{ #{arg} }")
24
+ TuplePredicate.new l, arg.to_s
25
+ when Hash
26
+ h = Tools.tuple_collect(arg){|k,v|
27
+ (AttrName === k) ?
28
+ [k,v] : [Tools.coerce(k, AttrName), Kernel.eval(v)]
29
+ }
30
+ source = h.each_pair.collect{|k,v|
31
+ "(self.#{k} == #{Tools.to_ruby_literal(v)})"
32
+ }.join(" && ")
33
+ coerce(source.empty? ? true : source)
34
+ when Array
35
+ (arg.size <= 1) ?
36
+ coerce(arg.first || true) :
37
+ coerce(Hash[*arg])
38
+ else
39
+ raise ArgumentError, "Invalid argument `#{arg}` for TupleExpression()"
40
+ end
41
+ end
42
+
43
+ def self.from_argv(argv)
44
+ coerce(argv)
45
+ end
46
+
47
+ end # class TuplePredicate
48
+ end # module Types
49
+ end # module Alf
data/lib/alf/version.rb CHANGED
@@ -2,8 +2,8 @@ module Alf
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 9
6
- TINY = 3
5
+ MINOR = 10
6
+ TINY = 0
7
7
 
8
8
  def self.to_s
9
9
  [ MAJOR, MINOR, TINY ].join('.')