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.
- data/CHANGELOG.md +255 -129
- data/Gemfile +31 -1
- data/Gemfile.lock +17 -20
- data/LICENCE.md +1 -1
- data/Manifest.txt +2 -0
- data/README.md +37 -43
- data/TODO.md +1 -1
- data/alf.gemspec +10 -7
- data/alf.noespec +24 -13
- data/bin/alf +2 -2
- data/doc/commands/exec.md +16 -0
- data/doc/commands/help.md +11 -0
- data/doc/commands/main.md +33 -0
- data/doc/commands/show.md +19 -0
- data/doc/operators/non_relational/autonum.md +23 -0
- data/doc/operators/non_relational/clip.md +31 -0
- data/doc/operators/non_relational/coerce.md +15 -0
- data/doc/operators/non_relational/compact.md +20 -0
- data/doc/operators/non_relational/defaults.md +32 -0
- data/doc/operators/non_relational/generator.md +20 -0
- data/doc/operators/non_relational/sort.md +24 -0
- data/doc/operators/relational/extend.md +18 -0
- data/doc/operators/relational/group.md +27 -0
- data/doc/operators/relational/intersect.md +13 -0
- data/doc/operators/relational/join.md +27 -0
- data/doc/operators/relational/matching.md +20 -0
- data/doc/operators/relational/minus.md +12 -0
- data/doc/operators/relational/not-matching.md +20 -0
- data/doc/operators/relational/project.md +28 -0
- data/doc/operators/relational/quota.md +21 -0
- data/doc/operators/relational/rank.md +27 -0
- data/doc/operators/relational/rename.md +17 -0
- data/doc/operators/relational/restrict.md +25 -0
- data/doc/operators/relational/summarize.md +25 -0
- data/doc/operators/relational/ungroup.md +20 -0
- data/doc/operators/relational/union.md +14 -0
- data/doc/operators/relational/unwrap.md +20 -0
- data/doc/operators/relational/wrap.md +24 -0
- data/examples/csv/suppliers.csv +6 -0
- data/examples/logs/access.log +1000 -0
- data/examples/logs/combined.alf +2 -0
- data/examples/logs/hits.alf +14 -0
- data/examples/logs/not_found.alf +7 -0
- data/examples/logs/robots-cheating.alf +11 -0
- data/examples/logs/robots.alf +8 -0
- data/examples/northwind/customers.csv +92 -0
- data/examples/northwind/northwind.db +0 -0
- data/examples/northwind/orders.csv +831 -0
- data/examples/operators/clip.alf +1 -1
- data/examples/operators/database.alf +5 -6
- data/examples/operators/defaults.alf +1 -1
- data/examples/operators/group.alf +1 -1
- data/examples/operators/project.alf +2 -1
- data/examples/operators/pseudo-with.alf +2 -2
- data/examples/operators/quota.alf +2 -2
- data/examples/operators/summarize.alf +2 -2
- data/lib/alf/aggregator/aggregators.rb +77 -0
- data/lib/alf/aggregator/base.rb +95 -0
- data/lib/alf/aggregator/class_methods.rb +57 -0
- data/lib/alf/buffer/sorted.rb +48 -0
- data/lib/alf/command/class_methods.rb +27 -0
- data/lib/alf/command/doc_manager.rb +72 -0
- data/lib/alf/command/exec.rb +12 -0
- data/lib/alf/command/help.rb +31 -0
- data/lib/alf/command/main.rb +146 -0
- data/lib/alf/command/show.rb +33 -0
- data/lib/alf/environment/base.rb +37 -0
- data/lib/alf/environment/class_methods.rb +93 -0
- data/lib/alf/environment/explicit.rb +38 -0
- data/lib/alf/environment/folder.rb +62 -0
- data/lib/alf/extra/csv.rb +104 -0
- data/lib/alf/extra/logs.rb +100 -0
- data/lib/alf/extra/sequel.rb +77 -0
- data/lib/alf/{yaml.rb → extra/yaml.rb} +0 -0
- data/lib/alf/extra.rb +5 -0
- data/lib/alf/iterator/base.rb +38 -0
- data/lib/alf/iterator/class_methods.rb +22 -0
- data/lib/alf/iterator/proxy.rb +33 -0
- data/lib/alf/lispy/instance_methods.rb +157 -0
- data/lib/alf/operator/base.rb +74 -0
- data/lib/alf/operator/binary.rb +32 -0
- data/lib/alf/operator/cesure.rb +45 -0
- data/lib/alf/operator/class_methods.rb +132 -0
- data/lib/alf/operator/experimental.rb +9 -0
- data/lib/alf/operator/non_relational/autonum.rb +24 -0
- data/lib/alf/operator/non_relational/clip.rb +20 -0
- data/lib/alf/operator/non_relational/coerce.rb +21 -0
- data/lib/alf/operator/non_relational/compact.rb +62 -0
- data/lib/alf/operator/non_relational/defaults.rb +25 -0
- data/lib/alf/operator/non_relational/generator.rb +38 -0
- data/lib/alf/operator/non_relational/sort.rb +23 -0
- data/lib/alf/operator/nullary.rb +20 -0
- data/lib/alf/operator/relational/extend.rb +24 -0
- data/lib/alf/operator/relational/group.rb +32 -0
- data/lib/alf/operator/relational/intersect.rb +37 -0
- data/lib/alf/operator/relational/join.rb +106 -0
- data/lib/alf/operator/relational/matching.rb +45 -0
- data/lib/alf/operator/relational/minus.rb +37 -0
- data/lib/alf/operator/relational/not_matching.rb +45 -0
- data/lib/alf/operator/relational/project.rb +22 -0
- data/lib/alf/operator/relational/quota.rb +51 -0
- data/lib/alf/operator/relational/rank.rb +55 -0
- data/lib/alf/operator/relational/rename.rb +19 -0
- data/lib/alf/operator/relational/restrict.rb +20 -0
- data/lib/alf/operator/relational/summarize.rb +83 -0
- data/lib/alf/operator/relational/ungroup.rb +25 -0
- data/lib/alf/operator/relational/union.rb +32 -0
- data/lib/alf/operator/relational/unwrap.rb +21 -0
- data/lib/alf/operator/relational/wrap.rb +22 -0
- data/lib/alf/operator/shortcut.rb +53 -0
- data/lib/alf/operator/signature.rb +262 -0
- data/lib/alf/operator/transform.rb +27 -0
- data/lib/alf/operator/unary.rb +38 -0
- data/lib/alf/reader/alf_file.rb +24 -0
- data/lib/alf/reader/base.rb +119 -0
- data/lib/alf/reader/class_methods.rb +82 -0
- data/lib/alf/reader/rash.rb +28 -0
- data/lib/alf/relation/class_methods.rb +37 -0
- data/lib/alf/relation/instance_methods.rb +127 -0
- data/lib/alf/renderer/base.rb +72 -0
- data/lib/alf/renderer/class_methods.rb +58 -0
- data/lib/alf/renderer/rash.rb +19 -0
- data/lib/alf/{text.rb → renderer/text.rb} +1 -1
- data/lib/alf/tools/coerce.rb +14 -0
- data/lib/alf/tools/miscellaneous.rb +77 -0
- data/lib/alf/tools/to_lispy.rb +99 -0
- data/lib/alf/tools/to_ruby_literal.rb +14 -0
- data/lib/alf/tools/tuple_handle.rb +50 -0
- data/lib/alf/types/attr_list.rb +56 -0
- data/lib/alf/types/attr_name.rb +28 -0
- data/lib/alf/types/boolean.rb +12 -0
- data/lib/alf/types/heading.rb +96 -0
- data/lib/alf/types/ordering.rb +93 -0
- data/lib/alf/types/renaming.rb +57 -0
- data/lib/alf/types/summarization.rb +76 -0
- data/lib/alf/types/tuple_computation.rb +61 -0
- data/lib/alf/types/tuple_expression.rb +61 -0
- data/lib/alf/types/tuple_predicate.rb +49 -0
- data/lib/alf/version.rb +2 -2
- data/lib/alf.rb +193 -3714
- data/spec/integration/__database__/group.alf +1 -1
- data/spec/integration/__database__/suppliers_csv.csv +6 -0
- data/spec/integration/command/alf/alf.db +0 -0
- data/spec/integration/command/alf/alf_env_sqlite.cmd +1 -0
- data/spec/integration/command/alf/alf_env_sqlite.stdout +9 -0
- data/spec/integration/command/alf/alf_help.cmd +1 -0
- data/spec/integration/command/alf/alf_help.stdout +67 -0
- data/spec/integration/command/autonum/autonum_0.cmd +1 -1
- data/spec/integration/command/coerce/coerce_1.cmd +1 -0
- data/spec/integration/command/coerce/coerce_1.stdout +5 -0
- data/spec/integration/command/defaults/defaults_0.cmd +1 -1
- data/spec/integration/command/defaults/defaults_0.stdout +9 -9
- data/spec/integration/command/defaults/defaults_2.cmd +1 -0
- data/spec/integration/command/defaults/defaults_2.stdout +9 -0
- data/spec/integration/command/generator/generator_1.cmd +1 -0
- data/spec/integration/command/generator/generator_1.stdout +10 -0
- data/spec/integration/command/generator/generator_2.cmd +1 -0
- data/spec/integration/command/generator/generator_2.stdout +5 -0
- data/spec/integration/command/generator/generator_3.cmd +1 -0
- data/spec/integration/command/generator/generator_3.stdout +5 -0
- data/spec/integration/command/group/group_0.cmd +1 -1
- data/spec/integration/command/group/group_1.cmd +1 -1
- data/spec/integration/command/help/help_1.cmd +1 -0
- data/spec/integration/command/help/help_1.stdout +22 -0
- data/spec/integration/command/quota/quota_0.cmd +1 -1
- data/spec/integration/command/rank/rank_1.cmd +1 -1
- data/spec/integration/command/rank/rank_1.stdout +10 -10
- data/spec/integration/command/rank/rank_2.cmd +1 -1
- data/spec/integration/command/rank/rank_2.stdout +10 -10
- data/spec/integration/command/rank/rank_3.cmd +1 -1
- data/spec/integration/command/rank/rank_3.stdout +10 -10
- data/spec/integration/command/rank/rank_4.cmd +1 -1
- data/spec/integration/command/rank/rank_5.cmd +1 -1
- data/spec/integration/command/show/show_csv.cmd +1 -0
- data/spec/integration/command/show/show_csv.stdout +6 -0
- data/spec/integration/command/show/show_rash_2.cmd +1 -1
- data/spec/integration/command/show/show_rash_2.stdout +5 -5
- data/spec/integration/command/sort/sort_0.cmd +1 -1
- data/spec/integration/command/sort/sort_1.cmd +1 -1
- data/spec/integration/command/sort/sort_1.stdout +2 -2
- data/spec/integration/command/sort/sort_2.cmd +1 -0
- data/spec/integration/command/sort/sort_2.stdout +9 -0
- data/spec/integration/command/sort/sort_3.cmd +1 -0
- data/spec/integration/command/sort/sort_3.stdout +9 -0
- data/spec/integration/command/summarize/summarize_0.cmd +1 -1
- data/spec/integration/command/ungroup/ungroup_0.cmd +1 -1
- data/spec/integration/command/wrap/wrap_0.cmd +1 -1
- data/spec/integration/semantics/test_project.alf +5 -6
- data/spec/integration/semantics/test_rank.alf +16 -16
- data/spec/integration/test_command.rb +17 -6
- data/spec/integration/test_examples.rb +1 -1
- data/spec/regression/logs/apache_combined.log +5 -0
- data/spec/regression/logs/test_path_attribute.rb +25 -0
- data/spec/regression/relation/test_relation_allbut_all.rb +14 -0
- data/spec/shared/an_operator_class.rb +10 -5
- data/spec/spec_helper.rb +1 -7
- data/spec/unit/assumptions/test_set.rb +64 -0
- data/spec/unit/command/doc_manager/dynamic.md +1 -0
- data/spec/unit/command/doc_manager/example.md +1 -0
- data/spec/unit/command/doc_manager/example_1.txt +11 -0
- data/spec/unit/command/doc_manager/static.md +1 -0
- data/spec/unit/command/doc_manager/test_call.rb +49 -0
- data/spec/unit/csv/input.csv +3 -0
- data/spec/unit/csv/test_reader.rb +66 -0
- data/spec/unit/csv/test_renderer.rb +73 -0
- data/spec/unit/lispy/test_relation.rb +37 -0
- data/spec/unit/lispy/test_run.rb +40 -0
- data/spec/unit/lispy/test_tuple.rb +36 -0
- data/spec/unit/logs/apache_combined.log +5 -0
- data/spec/unit/logs/postgresql.log +29 -0
- data/spec/unit/logs/test_reader.rb +56 -0
- data/spec/unit/operator/non_relational/compact/{buffer_based.rb → test_buffer_based.rb} +0 -0
- data/spec/unit/operator/non_relational/test_clip.rb +1 -1
- data/spec/unit/operator/non_relational/test_coerce.rb +35 -0
- data/spec/unit/operator/non_relational/test_defaults.rb +15 -2
- data/spec/unit/operator/non_relational/test_generator.rb +78 -0
- data/spec/unit/operator/relational/join/test_hash_based.rb +4 -4
- data/spec/unit/operator/relational/matching/test_hash_based.rb +6 -6
- data/spec/unit/operator/relational/not_matching/test_hash_based.rb +4 -4
- data/spec/unit/operator/relational/summarize/test_hash_based.rb +10 -6
- data/spec/unit/operator/relational/summarize/test_sort_based.rb +18 -7
- data/spec/unit/operator/relational/test_group.rb +8 -8
- data/spec/unit/operator/relational/test_intersect.rb +3 -3
- data/spec/unit/operator/relational/test_minus.rb +3 -3
- data/spec/unit/operator/relational/test_project.rb +12 -2
- data/spec/unit/operator/relational/test_quota.rb +5 -6
- data/spec/unit/operator/relational/test_summarize.rb +9 -11
- data/spec/unit/operator/relational/test_union.rb +1 -1
- data/spec/unit/operator/relational/test_wrap.rb +1 -1
- data/spec/unit/operator/signature/test_collect_on.rb +45 -0
- data/spec/unit/operator/signature/test_initialize.rb +17 -0
- data/spec/unit/operator/signature/test_install.rb +56 -0
- data/spec/unit/operator/signature/test_option_parser.rb +36 -0
- data/spec/unit/operator/signature/test_parse_args.rb +60 -0
- data/spec/unit/operator/signature/test_parse_argv.rb +87 -0
- data/spec/unit/operator/signature/test_to_lispy.rb +102 -0
- data/spec/unit/operator/signature/test_to_shell.rb +103 -0
- data/spec/unit/operator/test_non_relational.rb +3 -1
- data/spec/unit/relation/test_relops.rb +20 -15
- data/spec/unit/sequel/alf.db +0 -0
- data/spec/unit/sequel/test_environment.rb +54 -0
- data/spec/unit/test_aggregator.rb +32 -22
- data/spec/unit/test_environment.rb +5 -0
- data/spec/unit/test_lispy.rb +4 -0
- data/spec/unit/test_relation.rb +5 -0
- data/spec/unit/text/test_cell.rb +6 -6
- data/spec/unit/text/test_row.rb +3 -3
- data/spec/unit/text/test_table.rb +6 -6
- data/spec/unit/tools/test_coalesce.rb +15 -0
- data/spec/unit/tools/test_coerce.rb +10 -0
- data/spec/unit/tools/test_to_lispy.rb +138 -0
- data/spec/unit/tools/test_to_ruby_literal.rb +10 -0
- data/spec/unit/tools/test_tuple_handle.rb +1 -59
- data/spec/unit/types/test_attr_list.rb +106 -0
- data/spec/unit/types/test_attr_name.rb +52 -0
- data/spec/unit/{test_heading.rb → types/test_heading.rb} +10 -0
- data/spec/unit/types/test_ordering.rb +127 -0
- data/spec/unit/types/test_renaming.rb +55 -0
- data/spec/unit/types/test_summarization.rb +63 -0
- data/spec/unit/types/test_tuple_computation.rb +60 -0
- data/spec/unit/types/test_tuple_expression.rb +64 -0
- data/spec/unit/types/test_tuple_predicate.rb +79 -0
- data/tasks/debug_mail.rake +1 -1
- data/tasks/debug_mail.txt +5 -0
- data/tasks/gh-pages.rake +63 -0
- metadata +325 -52
- data/spec/unit/operator/test_command_methods.rb +0 -38
- data/spec/unit/tools/test_ordering_key.rb +0 -94
- data/spec/unit/tools/test_parse_commandline_args.rb +0 -47
- 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
|