locomotive 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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