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