glue 0.0.1 → 0.13.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 +19 -0
- data/INSTALL +56 -0
- data/README +3 -0
- data/Rakefile +73 -10
- data/doc/AUTHORS +16 -0
- data/doc/LICENSE +33 -0
- data/doc/RELEASES +5 -0
- data/install.rb +47 -0
- data/lib/glue.rb +57 -59
- data/lib/glue/array.rb +61 -0
- data/lib/glue/attribute.rb +83 -0
- data/lib/glue/cache.rb +138 -0
- data/lib/glue/flexob.rb +12 -0
- data/lib/glue/hash.rb +122 -0
- data/lib/glue/inflector.rb +91 -0
- data/lib/glue/logger.rb +147 -0
- data/lib/glue/misc.rb +14 -0
- data/lib/glue/mixins.rb +36 -0
- data/lib/glue/number.rb +24 -0
- data/lib/glue/object.rb +32 -0
- data/lib/glue/pool.rb +60 -0
- data/lib/glue/property.rb +408 -0
- data/lib/glue/string.rb +162 -0
- data/lib/glue/time.rb +85 -0
- data/lib/glue/validation.rb +461 -0
- data/test/glue/tc_attribute.rb +22 -0
- data/test/glue/tc_cache.rb +45 -0
- data/test/glue/tc_hash.rb +38 -0
- data/test/glue/tc_logger.rb +39 -0
- data/test/glue/tc_numbers.rb +20 -0
- data/test/glue/tc_property.rb +91 -0
- data/test/glue/tc_property_mixins.rb +93 -0
- data/test/glue/tc_property_type_checking.rb +35 -0
- data/test/glue/tc_strings.rb +103 -0
- data/test/glue/tc_validation.rb +214 -0
- metadata +95 -89
- data/History.txt +0 -6
- data/Manifest.txt +0 -7
- data/README.txt +0 -127
- data/bin/glue +0 -1
- data/test/test_glue.rb +0 -218
@@ -0,0 +1,83 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# Original code from Rails distribution.
|
3
|
+
# http://www.rubyonrails.com
|
4
|
+
# $Id$
|
5
|
+
|
6
|
+
#--
|
7
|
+
# Extends the module object with module and instance accessors
|
8
|
+
# for class attributes, just like the native attr* accessors for
|
9
|
+
# instance attributes. Aliases for classes are also provided.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# mattr_accessor :my_attr, 'Default value'
|
14
|
+
#++
|
15
|
+
class Module # :nodoc:
|
16
|
+
|
17
|
+
def mattr_reader(*params)
|
18
|
+
default = if params.last.is_a?(Symbol) then nil else params.pop end
|
19
|
+
|
20
|
+
|
21
|
+
for sym in params
|
22
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
23
|
+
|
24
|
+
if not defined?(@@#{sym.id2name})
|
25
|
+
@@#{sym.id2name} = #{default.inspect}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.#{sym.id2name}
|
29
|
+
@@#{sym}
|
30
|
+
end
|
31
|
+
|
32
|
+
def #{sym.id2name}
|
33
|
+
@@#{sym}
|
34
|
+
end
|
35
|
+
|
36
|
+
def call_#{sym.id2name}
|
37
|
+
case @@#{sym.id2name}
|
38
|
+
when Symbol then send(@@#{sym})
|
39
|
+
when Proc then @@#{sym}.call(self)
|
40
|
+
when String then @@#{sym}
|
41
|
+
else nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end_eval
|
46
|
+
end
|
47
|
+
end
|
48
|
+
alias_method :cattr_reader, :mattr_reader
|
49
|
+
|
50
|
+
def mattr_writer(*params)
|
51
|
+
default = if params.last.is_a?(Symbol) then nil else params.pop end
|
52
|
+
|
53
|
+
for sym in params
|
54
|
+
module_eval <<-"end_eval", __FILE__, __LINE__
|
55
|
+
|
56
|
+
if not defined?(@@#{sym.id2name})
|
57
|
+
@@#{sym.id2name} = #{default.inspect.inspect}
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.#{sym.id2name}=(obj)
|
61
|
+
@@#{sym.id2name} = obj
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.set_#{sym.id2name}(obj)
|
65
|
+
@@#{sym.id2name} = obj
|
66
|
+
end
|
67
|
+
|
68
|
+
def #{sym.id2name}=(obj)
|
69
|
+
@@#{sym} = obj
|
70
|
+
end
|
71
|
+
|
72
|
+
end_eval
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias_method :cattr_writer, :cattr_writer
|
76
|
+
|
77
|
+
def mattr_accessor(*syms)
|
78
|
+
mattr_reader(*syms)
|
79
|
+
mattr_writer(*syms)
|
80
|
+
end
|
81
|
+
alias_method :cattr_accessor, :mattr_accessor
|
82
|
+
|
83
|
+
end
|
data/lib/glue/cache.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# * Anastasios Koutoumanos <ak@navel.gr>
|
3
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
4
|
+
# $Id: cache.rb 282 2005-03-10 12:24:53Z gmosx $
|
5
|
+
|
6
|
+
module N
|
7
|
+
|
8
|
+
# A cache utilizing a simple LRU (Least Recently Used) policy.
|
9
|
+
# The items managed by this cache must respond to the #key method.
|
10
|
+
# Attempts to optimize reads rather than inserts!
|
11
|
+
#
|
12
|
+
# LRU semantics are enforced by inserting the items in a queue.
|
13
|
+
# The lru item is always at the tail. Two special sentinels
|
14
|
+
# (head, tail) are used to simplify (?) the code.
|
15
|
+
|
16
|
+
class LRUCache < Hash
|
17
|
+
|
18
|
+
# Mix this in your class to make LRU-managable.
|
19
|
+
|
20
|
+
module Item
|
21
|
+
attr_accessor :lru_key, :lru_prev, :lru_next
|
22
|
+
end
|
23
|
+
|
24
|
+
# head-tail sentinels
|
25
|
+
|
26
|
+
class Sentinel; include Item; end
|
27
|
+
|
28
|
+
# the maximum number of items in the cache.
|
29
|
+
|
30
|
+
attr_accessor :max_items
|
31
|
+
|
32
|
+
# the head sentinel
|
33
|
+
|
34
|
+
attr :head
|
35
|
+
|
36
|
+
# the tail sentinel, tail.prev points to the lru item.
|
37
|
+
|
38
|
+
attr :tail
|
39
|
+
|
40
|
+
def initialize(max_items)
|
41
|
+
@max_items = max_items
|
42
|
+
lru_clear()
|
43
|
+
end
|
44
|
+
|
45
|
+
# Lookup an item in the cache.
|
46
|
+
|
47
|
+
def [](key)
|
48
|
+
if item = super
|
49
|
+
return lru_touch(item)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# The inserted item is considered mru!
|
54
|
+
|
55
|
+
def []=(key, item)
|
56
|
+
item = super
|
57
|
+
item.lru_key = key
|
58
|
+
lru_insert(item)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Delete an item from the cache.
|
62
|
+
|
63
|
+
def delete(key)
|
64
|
+
if item = super
|
65
|
+
lru_delete(item)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clear the cache.
|
70
|
+
|
71
|
+
def clear
|
72
|
+
super
|
73
|
+
lru_clear()
|
74
|
+
end
|
75
|
+
|
76
|
+
# The first (mru) element in the cache.
|
77
|
+
|
78
|
+
def first
|
79
|
+
@head.lru_next
|
80
|
+
end
|
81
|
+
|
82
|
+
# The last (lru) element in the cache.
|
83
|
+
|
84
|
+
def last
|
85
|
+
@tail.lru_prev
|
86
|
+
end
|
87
|
+
alias_method :lru, :last
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# Delete an item from the lru list.
|
92
|
+
|
93
|
+
def lru_delete(item)
|
94
|
+
lru_join(item.lru_prev, item.lru_next)
|
95
|
+
return item
|
96
|
+
end
|
97
|
+
|
98
|
+
# Join two items in the lru list.
|
99
|
+
# Return y to allow for chaining.
|
100
|
+
|
101
|
+
def lru_join(x, y)
|
102
|
+
x.lru_next = y
|
103
|
+
y.lru_prev = x
|
104
|
+
return y
|
105
|
+
end
|
106
|
+
|
107
|
+
# Append a child item to a parent item in the lru list
|
108
|
+
# (Re)inserts the child in the list.
|
109
|
+
|
110
|
+
def lru_append(parent, child)
|
111
|
+
lru_join(child, parent.lru_next)
|
112
|
+
lru_join(parent, child)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Insert an item
|
116
|
+
|
117
|
+
def lru_insert(item)
|
118
|
+
delete(last.lru_key) if size() > @max_items
|
119
|
+
lru_append(@head, item)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Touch an item, make mru!
|
123
|
+
# Returns the item.
|
124
|
+
|
125
|
+
def lru_touch(item)
|
126
|
+
lru_append(@head, lru_delete(item))
|
127
|
+
end
|
128
|
+
|
129
|
+
# Clear the lru.
|
130
|
+
|
131
|
+
def lru_clear
|
132
|
+
@head = Sentinel.new
|
133
|
+
@tail = Sentinel.new
|
134
|
+
lru_join(@head, @tail)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/lib/glue/flexob.rb
ADDED
data/lib/glue/hash.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: hash.rb 282 2005-03-10 12:24:53Z gmosx $
|
4
|
+
|
5
|
+
require 'sync'
|
6
|
+
|
7
|
+
module N
|
8
|
+
|
9
|
+
# A thread-safe hash. We use a sync object instead of a mutex,
|
10
|
+
# because it is re-entrant. An exclusive lock is needed when
|
11
|
+
# writing, a shared lock IS NEEDED when reading
|
12
|
+
# uses the delegator pattern to allow for multiple
|
13
|
+
# implementations!
|
14
|
+
|
15
|
+
class SafeHash < Hash
|
16
|
+
attr :sync
|
17
|
+
|
18
|
+
# gmosx: delegator is not used.
|
19
|
+
#
|
20
|
+
def initialize(delegator = nil)
|
21
|
+
@sync = ::Sync.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
@sync.synchronize(::Sync::SH) { super }
|
26
|
+
end
|
27
|
+
|
28
|
+
def []=(key, value)
|
29
|
+
@sync.synchronize(::Sync::EX) { super }
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete(key)
|
33
|
+
@sync.synchronize(::Sync::EX) { super }
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear
|
37
|
+
@sync.synchronize(::Sync::EX) { super }
|
38
|
+
end
|
39
|
+
|
40
|
+
def size
|
41
|
+
@sync.synchronize(::Sync::SH) { super }
|
42
|
+
end
|
43
|
+
|
44
|
+
def values
|
45
|
+
@sync.synchronize(::Sync::SH) { super }
|
46
|
+
end
|
47
|
+
|
48
|
+
def keys
|
49
|
+
@sync.synchronize(::Sync::SH) { super }
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
# A thread-safe hash. We use a sync object instead of a mutex,
|
55
|
+
# because it is re-entrant. An exclusive lock is needed when
|
56
|
+
# writing, a shared lock IS NEEDED when reading.
|
57
|
+
#
|
58
|
+
# === Design
|
59
|
+
#
|
60
|
+
# This class uses the delegator pattern. However we dont use rubys
|
61
|
+
# delegation facilities, they are more general and powerfull than we
|
62
|
+
# need here (and slower). Instead a custom (but simple) solution is
|
63
|
+
# used.
|
64
|
+
#
|
65
|
+
# === Example
|
66
|
+
#
|
67
|
+
# hash = SafeHashDelegator.new(Hash.new)
|
68
|
+
# hash = SafeHashDelegator.new(Hash.new)
|
69
|
+
|
70
|
+
class SafeHashDelegator < Hash
|
71
|
+
attr :delegate, :sync
|
72
|
+
|
73
|
+
def initialize(delegate)
|
74
|
+
@delegate = delegate
|
75
|
+
@sync = ::Sync.new
|
76
|
+
end
|
77
|
+
|
78
|
+
def [](key)
|
79
|
+
@sync.synchronize(::Sync::SH) {
|
80
|
+
@delegate[key]
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def []=(key, value)
|
85
|
+
@sync.synchronize(::Sync::EX) {
|
86
|
+
@delegate[key] = value
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete(key)
|
91
|
+
@sync.synchronize(::Sync::EX) {
|
92
|
+
@delegate.delete(key)
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def clear
|
97
|
+
@sync.synchronize(::Sync::EX) {
|
98
|
+
@delegate.clear
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def size
|
103
|
+
@sync.synchronize(::Sync::SH) {
|
104
|
+
@delegate.size()
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
def values
|
109
|
+
@sync.synchronize(::Sync::SH) {
|
110
|
+
@delegate.values()
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def keys
|
115
|
+
@sync.synchronize(::Sync::SH) {
|
116
|
+
@delegate.keys()
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Code from RubyOnRails (http://www.rubyonrails.com)
|
2
|
+
# Copyright (c) 2004 David Heinemeier Hansson.
|
3
|
+
|
4
|
+
module N
|
5
|
+
|
6
|
+
# The Inflector transforms words from singular to plural,
|
7
|
+
# class names to table names, modulized class names to ones without,
|
8
|
+
# and class names to foreign keys.
|
9
|
+
|
10
|
+
module Inflector
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def pluralize(word)
|
14
|
+
result = word.dup
|
15
|
+
plural_rules.each do |(rule, replacement)|
|
16
|
+
break if result.gsub!(rule, replacement)
|
17
|
+
end
|
18
|
+
return result
|
19
|
+
end
|
20
|
+
|
21
|
+
def singularize(word)
|
22
|
+
result = word.dup
|
23
|
+
singular_rules.each do |(rule, replacement)|
|
24
|
+
break if result.gsub!(rule, replacement)
|
25
|
+
end
|
26
|
+
return result
|
27
|
+
end
|
28
|
+
|
29
|
+
def camelize(lower_case_and_underscored_word)
|
30
|
+
lower_case_and_underscored_word.gsub(/(^|_)(.)/){$2.upcase}
|
31
|
+
end
|
32
|
+
|
33
|
+
def underscore(camel_cased_word)
|
34
|
+
camel_cased_word.gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
|
35
|
+
end
|
36
|
+
|
37
|
+
def demodulize(class_name_in_module)
|
38
|
+
class_name_in_module.gsub(/^.*::/, '')
|
39
|
+
end
|
40
|
+
|
41
|
+
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
42
|
+
Inflector.underscore(Inflector.demodulize(class_name)) +
|
43
|
+
(separate_class_name_and_id_with_underscore ? "_id" : "id")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Convert a class to a name.
|
47
|
+
|
48
|
+
def name(klass)
|
49
|
+
Inflector.underscore(Inflector.demodulize(klass.to_s))
|
50
|
+
end
|
51
|
+
|
52
|
+
# Convert a class to a name in plural
|
53
|
+
|
54
|
+
def plural_name(klass)
|
55
|
+
Inflector.pluralize(Inflector.underscore(Inflector.demodulize(klass.to_s)))
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def plural_rules #:doc:
|
60
|
+
[
|
61
|
+
[/(x|ch|ss)$/, '\1es'], # search, switch, fix, box, process, address
|
62
|
+
[/([^aeiouy]|qu)y$/, '\1ies'], # query, ability, agency
|
63
|
+
[/(?:([^f])fe|([lr])f)$/, '\1\2ves'], # half, safe, wife
|
64
|
+
[/sis$/, 'ses'], # basis, diagnosis
|
65
|
+
[/([ti])um$/, '\1a'], # datum, medium
|
66
|
+
[/person$/, 'people'], # person, salesperson
|
67
|
+
[/man$/, 'men'], # man, woman, spokesman
|
68
|
+
[/child$/, 'children'], # child
|
69
|
+
[/s$/, 's'], # no change (compatibility)
|
70
|
+
[/$/, 's']
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
def singular_rules #:doc:
|
75
|
+
[
|
76
|
+
[/(x|ch|ss)es$/, '\1'],
|
77
|
+
[/([^aeiouy]|qu)ies$/, '\1y'],
|
78
|
+
[/([lr])ves$/, '\1f'],
|
79
|
+
[/([^f])ves$/, '\1fe'],
|
80
|
+
[/(analy|ba|diagno|parenthe|progno|synop|the)ses$/, '\1sis'],
|
81
|
+
[/([ti])a$/, '\1um'],
|
82
|
+
[/people$/, 'person'],
|
83
|
+
[/men$/, 'man'],
|
84
|
+
[/status$/, 'status'],
|
85
|
+
[/children$/, 'child'],
|
86
|
+
[/s$/, '']
|
87
|
+
]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|