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.
- data/lib/locomotive.rb +6 -0
- data/lib/locomotive/core_extensions.rb +6 -0
- data/lib/locomotive/core_extensions/array.rb +22 -0
- data/lib/locomotive/core_extensions/class.rb +47 -0
- data/lib/locomotive/core_extensions/hash.rb +7 -0
- data/lib/locomotive/core_extensions/inflector.rb +29 -0
- data/lib/locomotive/core_extensions/module.rb +77 -0
- data/lib/locomotive/core_extensions/symbol.rb +17 -0
- data/lib/locomotive/misc.rb +1 -0
- data/lib/locomotive/misc/type_check.rb +129 -0
- data/lib/locomotive/relational_algebra.rb +8 -0
- data/lib/locomotive/relational_algebra/attributes.rb +171 -0
- data/lib/locomotive/relational_algebra/operators.rb +15 -0
- data/lib/locomotive/relational_algebra/operators/abstraction.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/abstraction/lambda.rb +83 -0
- data/lib/locomotive/relational_algebra/operators/abstraction/variable.rb +65 -0
- data/lib/locomotive/relational_algebra/operators/aggregation.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/aggregation/aggr_builtin.rb +26 -0
- data/lib/locomotive/relational_algebra/operators/aggregation/aggregation.rb +76 -0
- data/lib/locomotive/relational_algebra/operators/basic_operators.rb +144 -0
- data/lib/locomotive/relational_algebra/operators/boolean.rb +4 -0
- data/lib/locomotive/relational_algebra/operators/boolean/and.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/boolean/basic_boolean.rb +66 -0
- data/lib/locomotive/relational_algebra/operators/boolean/not.rb +56 -0
- data/lib/locomotive/relational_algebra/operators/boolean/or.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/builtins.rb +3 -0
- data/lib/locomotive/relational_algebra/operators/builtins/arith_builtin.rb +37 -0
- data/lib/locomotive/relational_algebra/operators/builtins/basic_builtin.rb +20 -0
- data/lib/locomotive/relational_algebra/operators/builtins/function.rb +69 -0
- data/lib/locomotive/relational_algebra/operators/comparisons.rb +6 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/basic_comparison.rb +65 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/equal.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/greater.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/greater_equal.rb +14 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/less.rb +21 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/less_equal.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/error.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/error/error.rb +52 -0
- data/lib/locomotive/relational_algebra/operators/filter.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/filter/select.rb +50 -0
- data/lib/locomotive/relational_algebra/operators/join.rb +5 -0
- data/lib/locomotive/relational_algebra/operators/join/basic_join.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/join/cross.rb +28 -0
- data/lib/locomotive/relational_algebra/operators/join/equi_join.rb +61 -0
- data/lib/locomotive/relational_algebra/operators/join/predicates.rb +95 -0
- data/lib/locomotive/relational_algebra/operators/join/theta_join.rb +53 -0
- data/lib/locomotive/relational_algebra/operators/projections.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/projections/attach.rb +67 -0
- data/lib/locomotive/relational_algebra/operators/projections/projection.rb +106 -0
- data/lib/locomotive/relational_algebra/operators/ranking.rb +6 -0
- data/lib/locomotive/relational_algebra/operators/ranking/basic_ranking.rb +67 -0
- data/lib/locomotive/relational_algebra/operators/ranking/rank.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/ranking/rank_lists.rb +45 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_id.rb +24 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_number.rb +55 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_rank.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/serialization.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/serialization/basic_serialize.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/serialization/serialize_relation.rb +105 -0
- data/lib/locomotive/relational_algebra/operators/set.rb +4 -0
- data/lib/locomotive/relational_algebra/operators/set/basic_set.rb +24 -0
- data/lib/locomotive/relational_algebra/operators/set/difference.rb +11 -0
- data/lib/locomotive/relational_algebra/operators/set/distinct.rb +35 -0
- data/lib/locomotive/relational_algebra/operators/set/union.rb +11 -0
- data/lib/locomotive/relational_algebra/operators/tables.rb +3 -0
- data/lib/locomotive/relational_algebra/operators/tables/literal_table.rb +95 -0
- data/lib/locomotive/relational_algebra/operators/tables/nil.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/tables/ref_table.rb +75 -0
- data/lib/locomotive/relational_algebra/operators/typeing.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/typeing/cast.rb +59 -0
- data/lib/locomotive/relational_algebra/ordering.rb +30 -0
- data/lib/locomotive/relational_algebra/query_information.rb +666 -0
- data/lib/locomotive/relational_algebra/rel_alg_ast_node.rb +51 -0
- data/lib/locomotive/relational_algebra/rel_alg_exceptions.rb +15 -0
- data/lib/locomotive/relational_algebra/schema.rb +87 -0
- data/lib/locomotive/relational_algebra/types.rb +86 -0
- data/lib/locomotive/tree_helpers.rb +3 -0
- data/lib/locomotive/tree_helpers/annotations.rb +58 -0
- data/lib/locomotive/tree_helpers/ast.rb +99 -0
- data/lib/locomotive/tree_helpers/ast_traversal.rb +43 -0
- data/lib/locomotive/utils.rb +2 -0
- data/lib/locomotive/utils/relalg2xml.rb +239 -0
- data/lib/locomotive/utils/xml.rb +47 -0
- metadata +157 -0
data/lib/locomotive.rb
ADDED
|
@@ -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,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 @@
|
|
|
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
|