locomotive 0.0.1

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 (84) hide show
  1. data/lib/locomotive.rb +6 -0
  2. data/lib/locomotive/core_extensions.rb +6 -0
  3. data/lib/locomotive/core_extensions/array.rb +22 -0
  4. data/lib/locomotive/core_extensions/class.rb +47 -0
  5. data/lib/locomotive/core_extensions/hash.rb +7 -0
  6. data/lib/locomotive/core_extensions/inflector.rb +29 -0
  7. data/lib/locomotive/core_extensions/module.rb +77 -0
  8. data/lib/locomotive/core_extensions/symbol.rb +17 -0
  9. data/lib/locomotive/misc.rb +1 -0
  10. data/lib/locomotive/misc/type_check.rb +129 -0
  11. data/lib/locomotive/relational_algebra.rb +8 -0
  12. data/lib/locomotive/relational_algebra/attributes.rb +171 -0
  13. data/lib/locomotive/relational_algebra/operators.rb +15 -0
  14. data/lib/locomotive/relational_algebra/operators/abstraction.rb +2 -0
  15. data/lib/locomotive/relational_algebra/operators/abstraction/lambda.rb +83 -0
  16. data/lib/locomotive/relational_algebra/operators/abstraction/variable.rb +65 -0
  17. data/lib/locomotive/relational_algebra/operators/aggregation.rb +2 -0
  18. data/lib/locomotive/relational_algebra/operators/aggregation/aggr_builtin.rb +26 -0
  19. data/lib/locomotive/relational_algebra/operators/aggregation/aggregation.rb +76 -0
  20. data/lib/locomotive/relational_algebra/operators/basic_operators.rb +144 -0
  21. data/lib/locomotive/relational_algebra/operators/boolean.rb +4 -0
  22. data/lib/locomotive/relational_algebra/operators/boolean/and.rb +9 -0
  23. data/lib/locomotive/relational_algebra/operators/boolean/basic_boolean.rb +66 -0
  24. data/lib/locomotive/relational_algebra/operators/boolean/not.rb +56 -0
  25. data/lib/locomotive/relational_algebra/operators/boolean/or.rb +9 -0
  26. data/lib/locomotive/relational_algebra/operators/builtins.rb +3 -0
  27. data/lib/locomotive/relational_algebra/operators/builtins/arith_builtin.rb +37 -0
  28. data/lib/locomotive/relational_algebra/operators/builtins/basic_builtin.rb +20 -0
  29. data/lib/locomotive/relational_algebra/operators/builtins/function.rb +69 -0
  30. data/lib/locomotive/relational_algebra/operators/comparisons.rb +6 -0
  31. data/lib/locomotive/relational_algebra/operators/comparisons/basic_comparison.rb +65 -0
  32. data/lib/locomotive/relational_algebra/operators/comparisons/equal.rb +13 -0
  33. data/lib/locomotive/relational_algebra/operators/comparisons/greater.rb +13 -0
  34. data/lib/locomotive/relational_algebra/operators/comparisons/greater_equal.rb +14 -0
  35. data/lib/locomotive/relational_algebra/operators/comparisons/less.rb +21 -0
  36. data/lib/locomotive/relational_algebra/operators/comparisons/less_equal.rb +13 -0
  37. data/lib/locomotive/relational_algebra/operators/error.rb +1 -0
  38. data/lib/locomotive/relational_algebra/operators/error/error.rb +52 -0
  39. data/lib/locomotive/relational_algebra/operators/filter.rb +1 -0
  40. data/lib/locomotive/relational_algebra/operators/filter/select.rb +50 -0
  41. data/lib/locomotive/relational_algebra/operators/join.rb +5 -0
  42. data/lib/locomotive/relational_algebra/operators/join/basic_join.rb +9 -0
  43. data/lib/locomotive/relational_algebra/operators/join/cross.rb +28 -0
  44. data/lib/locomotive/relational_algebra/operators/join/equi_join.rb +61 -0
  45. data/lib/locomotive/relational_algebra/operators/join/predicates.rb +95 -0
  46. data/lib/locomotive/relational_algebra/operators/join/theta_join.rb +53 -0
  47. data/lib/locomotive/relational_algebra/operators/projections.rb +2 -0
  48. data/lib/locomotive/relational_algebra/operators/projections/attach.rb +67 -0
  49. data/lib/locomotive/relational_algebra/operators/projections/projection.rb +106 -0
  50. data/lib/locomotive/relational_algebra/operators/ranking.rb +6 -0
  51. data/lib/locomotive/relational_algebra/operators/ranking/basic_ranking.rb +67 -0
  52. data/lib/locomotive/relational_algebra/operators/ranking/rank.rb +9 -0
  53. data/lib/locomotive/relational_algebra/operators/ranking/rank_lists.rb +45 -0
  54. data/lib/locomotive/relational_algebra/operators/ranking/row_id.rb +24 -0
  55. data/lib/locomotive/relational_algebra/operators/ranking/row_number.rb +55 -0
  56. data/lib/locomotive/relational_algebra/operators/ranking/row_rank.rb +9 -0
  57. data/lib/locomotive/relational_algebra/operators/serialization.rb +2 -0
  58. data/lib/locomotive/relational_algebra/operators/serialization/basic_serialize.rb +9 -0
  59. data/lib/locomotive/relational_algebra/operators/serialization/serialize_relation.rb +105 -0
  60. data/lib/locomotive/relational_algebra/operators/set.rb +4 -0
  61. data/lib/locomotive/relational_algebra/operators/set/basic_set.rb +24 -0
  62. data/lib/locomotive/relational_algebra/operators/set/difference.rb +11 -0
  63. data/lib/locomotive/relational_algebra/operators/set/distinct.rb +35 -0
  64. data/lib/locomotive/relational_algebra/operators/set/union.rb +11 -0
  65. data/lib/locomotive/relational_algebra/operators/tables.rb +3 -0
  66. data/lib/locomotive/relational_algebra/operators/tables/literal_table.rb +95 -0
  67. data/lib/locomotive/relational_algebra/operators/tables/nil.rb +13 -0
  68. data/lib/locomotive/relational_algebra/operators/tables/ref_table.rb +75 -0
  69. data/lib/locomotive/relational_algebra/operators/typeing.rb +1 -0
  70. data/lib/locomotive/relational_algebra/operators/typeing/cast.rb +59 -0
  71. data/lib/locomotive/relational_algebra/ordering.rb +30 -0
  72. data/lib/locomotive/relational_algebra/query_information.rb +666 -0
  73. data/lib/locomotive/relational_algebra/rel_alg_ast_node.rb +51 -0
  74. data/lib/locomotive/relational_algebra/rel_alg_exceptions.rb +15 -0
  75. data/lib/locomotive/relational_algebra/schema.rb +87 -0
  76. data/lib/locomotive/relational_algebra/types.rb +86 -0
  77. data/lib/locomotive/tree_helpers.rb +3 -0
  78. data/lib/locomotive/tree_helpers/annotations.rb +58 -0
  79. data/lib/locomotive/tree_helpers/ast.rb +99 -0
  80. data/lib/locomotive/tree_helpers/ast_traversal.rb +43 -0
  81. data/lib/locomotive/utils.rb +2 -0
  82. data/lib/locomotive/utils/relalg2xml.rb +239 -0
  83. data/lib/locomotive/utils/xml.rb +47 -0
  84. metadata +157 -0
@@ -0,0 +1,6 @@
1
+ require "singleton"
2
+ require "locomotive/misc"
3
+ require "locomotive/core_extensions"
4
+ require "locomotive/tree_helpers"
5
+ require "locomotive/utils"
6
+ require "locomotive/relational_algebra"
@@ -0,0 +1,6 @@
1
+ require "locomotive/core_extensions/class.rb"
2
+ require "locomotive/core_extensions/module.rb"
3
+ require "locomotive/core_extensions/array.rb"
4
+ require "locomotive/core_extensions/hash.rb"
5
+ require "locomotive/core_extensions/inflector.rb"
6
+ require "locomotive/core_extensions/symbol.rb"
@@ -0,0 +1,22 @@
1
+ class Array
2
+ # Extracts options from a set of arguments. Removes and returns the last
3
+ # element in the array if it's a hash, otherwise returns a blank hash.
4
+ #
5
+ # def options(*args)
6
+ # args.extract_options!
7
+ # end
8
+ #
9
+ # options(1, 2) # => {}
10
+ # options(1, 2, :a => :b) # => {:a=>:b}
11
+ def extract_options!
12
+ last.is_a?(::Hash) ? pop : {}
13
+ end
14
+
15
+ def flatten_once
16
+ inject([]) { |v, e| v.concat(e)}
17
+ end
18
+
19
+ def to_hash
20
+ Hash[*self.flatten_once]
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ class Class
2
+ def cattr_reader(*syms)
3
+ syms.flatten.each do |sym|
4
+ next if sym.is_a?(Hash)
5
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
6
+ unless defined? @@#{sym} # unless defined? @@hair_colors
7
+ @@#{sym} = nil # @@hair_colors = nil
8
+ end # end
9
+ #
10
+ def self.#{sym} # def self.hair_colors
11
+ @@#{sym} # @@hair_colors
12
+ end # end
13
+ #
14
+ def #{sym} # def hair_colors
15
+ @@#{sym} # @@hair_colors
16
+ end # end
17
+ EOS
18
+ end
19
+ end
20
+
21
+ def cattr_writer(*syms)
22
+ options = syms.extract_options!
23
+ syms.flatten.each do |sym|
24
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
25
+ unless defined? @@#{sym} # unless defined? @@hair_colors
26
+ @@#{sym} = nil # @@hair_colors = nil
27
+ end # end
28
+ #
29
+ def self.#{sym}=(obj) # def self.hair_colors=(obj)
30
+ @@#{sym} = obj # @@hair_colors = obj
31
+ end # end
32
+ #
33
+ #{" #
34
+ def #{sym}=(obj) # def hair_colors=(obj)
35
+ @@#{sym} = obj # @@hair_colors = obj
36
+ end # end
37
+ " unless options[:instance_writer] == false } # # instance writer above is generated unless options[:instance_writer] == false
38
+ EOS
39
+ self.send("#{sym}=", yield) if block_given?
40
+ end
41
+ end
42
+
43
+ def cattr_accessor(*syms, &blk)
44
+ cattr_reader(*syms)
45
+ cattr_writer(*syms, &blk)
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ class Hash
2
+ def flip
3
+ self.collect do |k,v|
4
+ [v,k]
5
+ end.to_hash
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ module FerryCore
2
+
3
+ module Inflector
4
+ extend self
5
+
6
+ # Converts the string to UpperCamelCase
7
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
8
+ str = lower_case_and_underscored_word.to_s
9
+ if first_letter_in_uppercase then
10
+ str.gsub(/\/(.?)/) { "::#{$1.upcase}" }.
11
+ gsub(/(?:^|_)(.)/) { $1.upcase }
12
+ else
13
+ str[0].chr.downcase +
14
+ camelize(lower_case_and_underscored_word)[1..-1]
15
+ end
16
+ end
17
+
18
+ # the reverse to camelcase
19
+ def underscore(camel_cased_word)
20
+ camel_cased_word.to_s.gsub(/::/, '/').
21
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
22
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
23
+ tr("-", "_").
24
+ downcase
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,77 @@
1
+ module FerryCore
2
+
3
+ # extensions to enhance an object with some attributes
4
+ # and derive simple methods
5
+ module ModuleExtensions
6
+ private
7
+
8
+ def derive(method_name)
9
+ methods = {
10
+ :initialize => "
11
+ def #{method_name}(#{@attributes.join(',')})
12
+ #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")}
13
+ end",
14
+ :== => "
15
+ def ==(other)
16
+ #{name} === other &&
17
+ #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")}
18
+ end"
19
+ }
20
+ class_eval methods[method_name], __FILE__, __LINE__
21
+ end
22
+
23
+ public
24
+
25
+ # extend the instance with some new attributes
26
+ def attributes(*attrs)
27
+ @attributes = attrs
28
+ attr_reader(*attrs)
29
+ end
30
+
31
+ def deriving(*methods)
32
+ methods.each(&method(:derive))
33
+ end
34
+
35
+ # stolen from active_support
36
+ # reimplement it by time since it use deprecated string metaprogramming
37
+ def delegate(*methods)
38
+ options = methods.pop
39
+ unless options.is_a?(Hash) && to = options[:to]
40
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
41
+ end
42
+
43
+ if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
44
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
45
+ end
46
+
47
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
48
+
49
+ file, line = caller.first.split(':', 2)
50
+ line = line.to_i
51
+
52
+ methods.each do |method|
53
+ on_nil =
54
+ if options[:allow_nil]
55
+ 'return'
56
+ else
57
+ %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
58
+ end
59
+
60
+ module_eval(<<-EOS, file, line)
61
+ def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
62
+ #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
63
+ rescue NoMethodError # rescue NoMethodError
64
+ if #{to}.nil? # if client.nil?
65
+ #{on_nil}
66
+ else # else
67
+ raise # raise
68
+ end # end
69
+ end # end
70
+ EOS
71
+ end
72
+ end
73
+
74
+ Module.send :include, self
75
+ end
76
+
77
+ end
@@ -0,0 +1,17 @@
1
+ module FerryCore
2
+
3
+ module SymbolExtensions
4
+
5
+ def classify
6
+ Inflector::camelize(self).to_sym
7
+ end
8
+
9
+ def methify
10
+ Inflector::underscore(
11
+ self.to_s.split("::").last).to_sym
12
+ end
13
+
14
+ Symbol.send :include, self
15
+ end
16
+
17
+ end
@@ -0,0 +1 @@
1
+ require 'locomotive/misc/type_check'
@@ -0,0 +1,129 @@
1
+ module Locomotive
2
+
3
+ module TypeChecking
4
+
5
+ class ArgumentError < StandardError; end
6
+
7
+ #
8
+ # Type checking method parameters
9
+ #
10
+ module TypeChecker
11
+
12
+ private
13
+
14
+ def nth n
15
+ n_ = n + 1
16
+ th = case n_
17
+ when 1 then 'st'
18
+ when 2 then 'nd'
19
+ else 'th'
20
+ end
21
+ "#{n_}#{th}"
22
+ end
23
+
24
+ public
25
+
26
+ # check a simple argument type
27
+ def check_arg_type(expected, obj, mtd, n=0)
28
+ unless obj.kind_of? expected
29
+ raise ArgumentError,
30
+ "#{obj.class} assigned to #{expected} " \
31
+ "for the #{nth n} argument of #{mtd}."
32
+ end
33
+ end
34
+
35
+ # check an array type
36
+ def check_arg_array_type(elem_type, arg, mtd, n=0)
37
+ check_arg_type Array, arg, mtd, n
38
+ arg.each_with_index do |x,i|
39
+ unless x.kind_of? elem_type
40
+ raise ArgumentError,
41
+ "#{x.class} assigned to #{elem_type} for " \
42
+ "the #{nth n} element of the #{nth n} " \
43
+ "argument of #{mtd}."
44
+ end
45
+ end
46
+ end
47
+
48
+ # check a hash type
49
+ def check_arg_hash_type(key_type, elem_type, arg, mtd, n=0)
50
+ check_arg_type Hash, arg, mtd, n
51
+ arg.each_with_index do |item,i|
52
+ check_arg_type key_type, item.first, mtd, n
53
+ check_arg_type elem_type, item.last, mtd, n if elem_type.kind_of? Class
54
+ check_arg_array_type elem_type.first, item.last, mtd, n if elem_type.kind_of? Array
55
+ end
56
+ end
57
+
58
+ # check a variable argument type
59
+ def check_vararg_type(expected, args, mtd, n=0)
60
+ (n..args.length).each do |i|
61
+ check_arg_type expected, args[i], mtd, i
62
+ end
63
+ end
64
+
65
+ # make 'class'-methods out of the
66
+ # methods defined above
67
+ extend self
68
+ end
69
+
70
+ #
71
+ # Add declarative signature support
72
+ #
73
+ module Signature
74
+
75
+ private
76
+
77
+ def intercept_method(sym, types)
78
+ # get the unbound method object
79
+ mtd = instance_method(sym)
80
+ helper = "_#{sym}_param_types_checked_helper".to_sym
81
+
82
+ define_method(helper) do |*params|
83
+ star_type, star_ind = nil, nil
84
+ types.each_with_index do |t,i|
85
+ t = star_type unless star_type.nil?
86
+ arg = params[i]
87
+ if t.kind_of? Class
88
+ TypeChecker.check_arg_type t, arg, sym, i
89
+ elsif t.empty?
90
+ TypeChecker.check_arg_type Array, arg, sym, i
91
+ elsif t.kind_of? Array
92
+ TypeChecker.check_arg_array_type t[0], arg, sym, i
93
+ elsif t.kind_of? Hash
94
+ TypeChecker.check_arg_hash_type t.first.first,
95
+ t.first.last,
96
+ arg, sym, i
97
+ else
98
+ star_type, star_ind = t[0], i
99
+ break
100
+ end
101
+ end
102
+ TypeChecker.check_vararg_type star_type, params, sym, star_ind unless star_ind.nil?
103
+ mtd.bind(self)
104
+ end
105
+ module_eval do
106
+ define_method(sym) do |*params, &block|
107
+ method(helper).call(*params).call(*params, &block)
108
+ end
109
+ end
110
+ end
111
+
112
+ public
113
+
114
+ def def_sig sym, *types
115
+ types.each_with_index do |t,i|
116
+ unless t.kind_of? Class
117
+ TypeChecker.check_arg_type Class, t, :def_sig, i unless t.kind_of? Array or t.kind_of? Hash
118
+ TypeChecker.check_arg_type Class, t, :def_sig, i unless t.length <= 1
119
+ TypeChecker.check_arg_array_type Class, t, :def_sig, i if t.kind_of? Array
120
+ end
121
+ end
122
+ intercept_method(sym, types)
123
+ end
124
+ Module.send(:include, self)
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,8 @@
1
+ require 'locomotive/relational_algebra/rel_alg_ast_node'
2
+ require 'locomotive/relational_algebra/rel_alg_exceptions'
3
+ require 'locomotive/relational_algebra/attributes'
4
+ require 'locomotive/relational_algebra/types'
5
+ require 'locomotive/relational_algebra/schema'
6
+ require 'locomotive/relational_algebra/ordering'
7
+ require 'locomotive/relational_algebra/operators'
8
+ require 'locomotive/relational_algebra/query_information'
@@ -0,0 +1,171 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+
6
+ class GenericAttribute; end
7
+
8
+ class ConstAttribute < GenericAttribute
9
+ protected
10
+
11
+ def nth id
12
+ if id == 0
13
+ ""
14
+ else
15
+ id.to_s
16
+ end
17
+ end
18
+
19
+ # we only accept positive integers as ids
20
+ def id=(id)
21
+ raise IdError, "#{id} less than 0" if id < 0
22
+ @id = id
23
+ end
24
+ def_sig :id=, Fixnum
25
+
26
+ public
27
+
28
+ attr_reader :id
29
+
30
+ def initialize(id=0)
31
+ raise AbstractClassError,
32
+ "#{self.class} is an abstract class" if self.class == ConstAttribute
33
+ self.id = id
34
+ end
35
+
36
+
37
+ def inc(val=1)
38
+ self.class.new(self.id + val)
39
+ end
40
+
41
+ def to_xml
42
+ # Be careful of classes that are nested in modules
43
+ "#{self.class.to_s.split("::").last.downcase}#{nth id}".to_sym
44
+ end
45
+
46
+ # Equality for attributes is defined over
47
+ # their class and id
48
+ def ==(other)
49
+ self.class == other.class and
50
+ self.id == other.id
51
+ end
52
+
53
+ module HashKeys
54
+ # We want to use attributes as keys
55
+ # for a hash-object, so we have to
56
+ # overwrite the eql?- and hash-method
57
+ # to make it work
58
+ def eql?(other)
59
+ self.==(other)
60
+ end
61
+ def_sig :eql?, ConstAttribute
62
+
63
+ def hash
64
+ # not the best algorithm for calculating a
65
+ # hash but it works quite well
66
+ self.class.object_id + id.object_id
67
+ end
68
+ end
69
+ include HashKeys
70
+
71
+ def clone
72
+ # an attributes contains only an id
73
+ self.class.new(id)
74
+ end
75
+
76
+ def inspect
77
+ "<#{self.class.to_s.split('::').last} #{id}>"
78
+ end
79
+ end
80
+
81
+ class Iter < ConstAttribute; end
82
+ def Iter(id)
83
+ Iter.new(id)
84
+ end
85
+ class Outer < Iter; end
86
+ def Outer(id)
87
+ Outer.new(id)
88
+ end
89
+ class Inner < Iter; end
90
+ def Inner(id)
91
+ Inner.new(id)
92
+ end
93
+ class Pos < ConstAttribute; end
94
+ def Pos(id)
95
+ Pos.new(id)
96
+ end
97
+ class Item < ConstAttribute
98
+
99
+ include Comparable
100
+ def <=>(other)
101
+ self.id <=> other.id
102
+ end
103
+ def_sig :<=>, Item
104
+
105
+ def inc!(id)
106
+ self.id += id
107
+ end
108
+
109
+ def dec!(id)
110
+ self.id -= id
111
+ end
112
+
113
+ end
114
+ def Item(id)
115
+ Item.new(id)
116
+ end
117
+
118
+ class Attribute < GenericAttribute
119
+ attr_reader :name
120
+
121
+ def initialize(name)
122
+ @name = name.to_s
123
+ end
124
+
125
+ # Equality for attributes is defined over
126
+ # their class their name
127
+ def ==(other)
128
+ self.class == other.class and
129
+ self.name == other.name
130
+ end
131
+
132
+ module HashKeys
133
+ # We want to use attributes as keys
134
+ # for a hash-object, so we have to
135
+ # overwrite the eql?- and hash-method
136
+ # to make it work
137
+ def eql?(other)
138
+ self.==(other)
139
+ end
140
+ def_sig :eql?, Attribute
141
+
142
+ def hash
143
+ # not the best algorithm for calculating a
144
+ # hash but it works quite well
145
+ self.class.object_id + name.object_id
146
+ end
147
+ end
148
+ include HashKeys
149
+
150
+ def to_xml
151
+ # Be careful of classes that are nested in modules
152
+ name
153
+ end
154
+
155
+
156
+ def inspect
157
+ "<#{self.class.to_s.split('::').last} name:#{name}>"
158
+ end
159
+
160
+ def clone
161
+ # an attributes contains only an id
162
+ Attribute.new(name)
163
+ end
164
+ end
165
+ def Attribute(name)
166
+ Attribute.new(name)
167
+ end
168
+
169
+ end
170
+
171
+ end