glue 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/CHANGELOG +161 -110
  2. data/INSTALL +12 -12
  3. data/README +1 -1
  4. data/Rakefile +43 -45
  5. data/doc/AUTHORS +5 -5
  6. data/doc/LICENSE +3 -3
  7. data/doc/RELEASES +32 -24
  8. data/install.rb +7 -17
  9. data/lib/facet/object/alias_class.rb +12 -0
  10. data/lib/glue.rb +35 -35
  11. data/lib/glue/array.rb +46 -46
  12. data/lib/glue/aspects.rb +199 -209
  13. data/lib/glue/attribute.rb +15 -15
  14. data/lib/glue/autoreload.rb +1 -1
  15. data/lib/glue/builder.rb +48 -0
  16. data/lib/glue/builder/xml.rb +114 -0
  17. data/lib/glue/cache.rb +189 -0
  18. data/lib/glue/configuration.rb +108 -90
  19. data/lib/glue/flexob.rb +17 -17
  20. data/lib/glue/hash.rb +71 -71
  21. data/lib/glue/helper.rb +12 -12
  22. data/lib/glue/idgen.rb +9 -0
  23. data/lib/glue/idgen/md5.rb +24 -0
  24. data/lib/glue/idgen/sequential.rb +15 -0
  25. data/lib/glue/literal_method.rb +44 -0
  26. data/lib/glue/localization.rb +130 -0
  27. data/lib/glue/logger.rb +98 -98
  28. data/lib/glue/misc.rb +7 -7
  29. data/lib/glue/mixins.rb +19 -19
  30. data/lib/glue/number.rb +8 -8
  31. data/lib/glue/object.rb +2 -2
  32. data/lib/glue/pool.rb +43 -43
  33. data/lib/glue/property.rb +392 -392
  34. data/lib/glue/sanitize.rb +34 -34
  35. data/lib/glue/settings.rb +1 -1
  36. data/lib/glue/snapshot.rb +104 -0
  37. data/lib/glue/string.rb +129 -129
  38. data/lib/glue/time.rb +53 -53
  39. data/lib/glue/uri.rb +162 -162
  40. data/lib/glue/validation.rb +421 -421
  41. data/lib/vendor/blankslate.rb +53 -0
  42. data/test/glue/builder/tc_xml.rb +56 -0
  43. data/test/glue/tc_aspects.rb +90 -90
  44. data/test/glue/tc_attribute.rb +11 -11
  45. data/test/glue/tc_builder.rb +30 -0
  46. data/test/glue/tc_configuration.rb +97 -97
  47. data/test/glue/tc_flexob.rb +10 -10
  48. data/test/glue/tc_hash.rb +23 -23
  49. data/test/glue/tc_localization.rb +49 -0
  50. data/test/glue/tc_logger.rb +31 -31
  51. data/test/glue/tc_numbers.rb +9 -9
  52. data/test/glue/tc_property.rb +67 -67
  53. data/test/glue/tc_property_mixins.rb +17 -17
  54. data/test/glue/tc_property_type_checking.rb +13 -13
  55. data/test/glue/tc_strings.rb +94 -94
  56. data/test/glue/tc_uri.rb +65 -65
  57. data/test/glue/tc_validation.rb +196 -196
  58. metadata +26 -4
@@ -24,7 +24,7 @@ def autoreload(check_interval=10)
24
24
  end
25
25
  end
26
26
  end
27
- }
27
+ }
28
28
  end
29
29
 
30
30
  end
@@ -0,0 +1,48 @@
1
+ module Glue
2
+
3
+ # A Builder integrates a number of Modules containing text
4
+ # manipulation utilities and provides an alternative
5
+ # 'accomulation' interface.
6
+
7
+ class Builder
8
+
9
+ # The builder output is accomulated in the buffer.
10
+
11
+ attr_accessor :buffer
12
+
13
+ class << self
14
+
15
+ def include_builder(*modules)
16
+ for mod in modules
17
+ include mod
18
+ for meth in mod.public_instance_methods
19
+ self.module_eval %{
20
+ alias_method :_mixin_#{meth}, :#{meth}
21
+ def #{meth}(*args)
22
+ @buffer << _mixin_#{meth}(*args)
23
+ return self
24
+ end
25
+ }
26
+ end
27
+ end
28
+ end
29
+ alias_method :builder, :include_builder
30
+
31
+ end
32
+
33
+ # Provide the target where the builder output will be
34
+ # accomulated. The builder utilizes duck typing to make it
35
+ # compatible with anly target responding to <<.
36
+
37
+ def initialize(buffer = '', *modules)
38
+ @buffer = buffer
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ # * George Moschovitis <gm@navel.gr>
47
+
48
+ __END__
@@ -0,0 +1,114 @@
1
+ require 'glue/builder'
2
+
3
+ require 'nitro/mixin/xhtml'
4
+ require 'nitro/mixin/form'
5
+ require 'nitro/mixin/table'
6
+
7
+ module Glue
8
+
9
+ # A Builder for programmatically building XML blocks.
10
+ #--
11
+ # TODO: move to nitro or move mixins here.
12
+ #++
13
+
14
+ class XmlBuilder < Builder
15
+ include_builder Nitro::XhtmlMixin
16
+ include_builder Nitro::TableMixin
17
+ include_builder Nitro::FormMixin
18
+
19
+ def method_missing(tag, *args, &block)
20
+ self.class.module_eval <<-"end_eval", __FILE__, __LINE__
21
+ def #{tag}(*args)
22
+ attrs = args.last.is_a?(Hash) ? args.pop : nil
23
+
24
+ if block_given?
25
+ start_tag!('#{tag}', attrs)
26
+ yield
27
+ end_tag!('#{tag}')
28
+ elsif (!args.empty?)
29
+ start_tag!('#{tag}', attrs)
30
+ @buffer << args.first
31
+ end_tag!('#{tag}')
32
+ else
33
+ start_tag!('#{tag}', attrs, false)
34
+ @buffer << ' />'
35
+ end
36
+
37
+ return self
38
+ end
39
+ end_eval
40
+
41
+ self.send(tag, *args, &block)
42
+ end
43
+
44
+ # Emit the start (opening) tag of an element.
45
+
46
+ def start_tag!(tag, attributes = nil, close = true)
47
+ unless attributes
48
+ if close
49
+ @buffer << "<#{tag}>"
50
+ else
51
+ @buffer << "<#{tag}"
52
+ end
53
+ else
54
+ @buffer << "<#{tag}"
55
+ for name, value in attributes
56
+ if value
57
+ @buffer << %| #{name}="#{value}"|
58
+ else
59
+ @buffer << %| #{name}="1"|
60
+ end
61
+ end
62
+ @buffer << ">" if close
63
+ end
64
+
65
+ return self
66
+ end
67
+
68
+ # Emit the end (closing) tag of an element.
69
+
70
+ def end_tag!(tag)
71
+ @buffer << "</#{tag}>"
72
+
73
+ return self
74
+ end
75
+
76
+ # Emit a text string.
77
+
78
+ def text!(str)
79
+ @buffer << str
80
+
81
+ return self
82
+ end
83
+ alias_method :print, :text!
84
+
85
+ # Emit a comment.
86
+
87
+ def comment!(str)
88
+ @buffer << "<!-- #{str} -->"
89
+
90
+ return self
91
+ end
92
+
93
+ # Emit a processing instruction.
94
+
95
+ def processing_instruction!(name, attributes = nil)
96
+ unless attributes
97
+ @buffer << "<?#{name} ?>"
98
+ else
99
+ @buffer << "<?#{name} "
100
+ attributes.each do |a, v|
101
+ @buffer << %[#{a}="#{v}" ]
102
+ end
103
+ @buffer << "?>"
104
+ end
105
+
106
+ return self
107
+ end
108
+ alias_method :pi!, :processing_instruction!
109
+
110
+ end
111
+
112
+ end
113
+
114
+ # * George Moschovitis <gm@navel.gr>
data/lib/glue/cache.rb ADDED
@@ -0,0 +1,189 @@
1
+ unless Enumerable.instance_methods.include?("min_by")
2
+ # for Ruby 1.8
3
+ module Enumerable
4
+ def min_by(&block)
5
+ min {|i,j| block.call(i) <=> block.call(j) }
6
+ end
7
+ end
8
+ end
9
+
10
+ module Glue
11
+
12
+ # Abstract super class of all cache implementations.
13
+ class Cache; end
14
+
15
+ # Abstract super class of all caching strategies.
16
+ class Cache::Strategy; end
17
+
18
+ # Implements an unbounded cache strategy. The cache size can
19
+ # grow to infinity.
20
+
21
+ class Cache::Strategy::Unbounded < Cache::Strategy
22
+ class Item < Struct.new(:value); end
23
+ def item_class() Item end
24
+
25
+ def access(item) end
26
+ def delete(item) end
27
+ def insert_or_extrude(item, enum) end
28
+ end
29
+
30
+ # Abstract class for a capacity bounded strategy. Only up to
31
+ # _capacity_ items are allowed to be stored in the cache
32
+ # at any time.
33
+
34
+ class Cache::Strategy::CapacityBounded < Cache::Strategy
35
+ attr_accessor :capacity
36
+
37
+ def initialize(capacity)
38
+ @capacity = capacity
39
+ @n_items = 0 # number of items in cache
40
+ end
41
+
42
+ def inc(item)
43
+ raise if full?
44
+ @n_items += 1
45
+ end
46
+
47
+ def dec(item)
48
+ raise if empty?
49
+ @n_items -= 1
50
+ end
51
+
52
+ def full?
53
+ @n_items >= @capacity
54
+ end
55
+
56
+ def empty?
57
+ @n_items == 0
58
+ end
59
+ end
60
+
61
+ # Implements the least frequently used (LFU) strategy.
62
+
63
+ class Cache::Strategy::LFU < Cache::Strategy::CapacityBounded
64
+ class Item < Struct.new(:value, :freq); end
65
+ def item_class() Item end
66
+
67
+ def access(item)
68
+ item.freq += 1
69
+ end
70
+
71
+ def delete(item)
72
+ dec(item)
73
+ end
74
+
75
+ # enum::
76
+ # a [key, item] enumerable
77
+
78
+ def insert_or_extrude(item, enum)
79
+ # find least recently used key/item and yield
80
+ yield enum.min_by {|key, it| it.freq} while full?
81
+ item.freq = 0
82
+ inc(item)
83
+ end
84
+ end
85
+
86
+ # Implements the least recently used (LRU) strategy.
87
+
88
+ class Cache::Strategy::LRU < Cache::Strategy::CapacityBounded
89
+ class Item < Struct.new(:value, :time); end
90
+ def item_class() Item end
91
+
92
+ def access(item)
93
+ item.time = Time.now
94
+ end
95
+
96
+ def delete(item)
97
+ dec(item)
98
+ end
99
+
100
+ # enum::
101
+ # a [key, item] enumerable
102
+ #
103
+ def insert_or_extrude(item, enum)
104
+ # find least recently used key/item and yield
105
+ yield enum.min_by {|key, it| it.time} while full?
106
+ item.time = Time.now
107
+ inc(item)
108
+ end
109
+ end
110
+
111
+ # Implements a cache using a parameterizable strategy and a storage.
112
+ # The protocol that the _store_ must understand is:
113
+ #
114
+ # fetch(key) -> val
115
+ # has_key?(key)
116
+ # delete(key) -> val
117
+ # each {|key, val| }
118
+
119
+ class Cache::StorageCache < Cache
120
+
121
+ def initialize(strategy, store=Hash.new, store_on_update=false)
122
+ @strategy = strategy
123
+ @store = store
124
+ @store_on_update = store_on_update
125
+ end
126
+
127
+ def has_key?(key)
128
+ @store.has_key?(key)
129
+ end
130
+
131
+ def delete(key)
132
+ if @store.has_key?(key)
133
+ item = @store.delete(key)
134
+ @strategy.delete(item)
135
+ item.value
136
+ else
137
+ nil
138
+ end
139
+ end
140
+
141
+ def fetch(key, default_value=nil)
142
+ if @store.has_key?(key)
143
+ item = @store.fetch(key)
144
+ @strategy.access(item)
145
+ @store.store(key, item) if @store_on_update
146
+ item.value
147
+ else
148
+ default_value
149
+ end
150
+ end
151
+
152
+ def store(key, value)
153
+ if @store.has_key?(key)
154
+ # update only
155
+ item = @store.fetch(key)
156
+ item.value = value
157
+ @strategy.access(item)
158
+ @store.store(key, item) if @store_on_update
159
+ else
160
+ # insert new item
161
+ item = @strategy.item_class.new
162
+ item.value = value
163
+ @strategy.insert_or_extrude(item, @store) do |k, i|
164
+ @strategy.delete(i)
165
+ @store.delete(k)
166
+ end
167
+ @store.store(key, item) # correct!
168
+ end
169
+ value
170
+ end
171
+
172
+ alias [] fetch
173
+ alias []= store
174
+ end
175
+
176
+ # Implements an in-memory cache (uses a Hash as store) with a LRU replacement
177
+ # stragegy.
178
+
179
+ class Cache::MemoryLRUCache < Cache::StorageCache
180
+ DEFAULT_CAPACITY = 20
181
+
182
+ def initialize(capacity=DEFAULT_CAPACITY)
183
+ super(Cache::Strategy::LRU.new(capacity))
184
+ end
185
+ end
186
+
187
+ end # module Glue
188
+
189
+ # * Michael Neumann <mneumann@ntecs.de>
@@ -14,87 +14,105 @@ require 'glue/flexob'
14
14
 
15
15
  class Configuration
16
16
 
17
- # A hash of setting owners. Use double @'s to allow for
18
- # the Settings alias.
19
- #--
20
- # TODO: find a better name.
21
- #++
22
-
23
- @@owners = Glue::SafeHash.new
17
+ # A hash of setting owners. Use double @'s to allow for
18
+ # the Settings alias.
19
+ #--
20
+ # TODO: find a better name.
21
+ #++
22
+
23
+ @@owners = Glue::SafeHash.new
24
24
 
25
- # A datastructure to store Settings metadata.
26
-
27
- class Setting
28
- attr_accessor :owner, :name, :type, :value, :options
29
-
30
- def initialize(owner, name, options)
31
- raise ArgumentError.new('A default value is required') unless options.key?(:default)
32
- @owner, @name = owner, name
33
- @options = options
34
- @value = options[:default]
35
- @type = options[:type] = options[:type] || @value.class
36
- end
25
+ # A datastructure to store Settings metadata.
26
+
27
+ class Setting
28
+ attr_accessor :owner, :name, :type, :value, :options
29
+
30
+ def initialize(owner, name, options)
31
+ raise ArgumentError.new('A default value is required') unless options.key?(:default)
32
+ @owner, @name = owner, name
33
+ @options = options
34
+ @value = options[:default]
35
+ @type = options[:type] = options[:type] || @value.class
36
+ end
37
37
 
38
- def value=(value)
39
- @value = value
40
- constant(@owner).module_eval %{
41
- @@#{@name} = #{value.inspect}
42
- }
43
- end
38
+ def value=(value)
39
+ @value = value
40
+ constant(@owner).module_eval %{
41
+ @@#{@name} = #{value.inspect}
42
+ }
43
+ end
44
44
 
45
- def to_s
46
- @value.to_s
47
- end
48
- end
49
-
50
- class << self
51
-
52
- def setup(options)
53
- options.each do |owner, ss|
54
- owner = constant(owner)
55
- ss.each do |name, s|
56
- @@owners[owner][name.to_sym].value = s
57
- owner.module_eval %{
58
- @@#{name} = #{s.inspect}
59
- }
60
- end
61
- end
62
- end
45
+ def to_s
46
+ @value.to_s
47
+ end
48
+ end
49
+
50
+ class << self
51
+
52
+ # Inject the configuration parameters to configuration
53
+ # classes.
54
+
55
+ def setup(options)
56
+ options.each do |owner, ss|
57
+ next unless ss
58
+ begin
59
+ owner = constant(owner)
60
+ rescue NameError
61
+ next
62
+ end
63
+ ss.each do |name, s|
64
+ @@owners[owner][name.to_sym].value = s
65
+ owner.module_eval %{
66
+ @@#{name} = #{s.inspect}
67
+ }
68
+ end
69
+ end
70
+ end
63
71
 
64
- def parse(options)
65
- temp = YAML::load(options)
66
- options = {}
67
- temp.each { |k, v| options[constant(k.gsub(/\./, '::').to_sym)] = v }
68
- setup(options)
69
- end
70
-
71
- def load(filename)
72
- parse(File.read(filename))
73
- end
74
-
75
- def add_setting(owner, name, options)
76
- s = @@owners[owner] || {}
77
- s[name] = Setting.new(owner, name, options)
78
- @@owners[owner] = s
79
- end
80
-
81
- def settings(owner = nil)
82
- if owner
83
- @@owners[owner]
84
- else
85
- @@owners.values.inject([]) { |memo, obj| memo.concat(obj.values) }
86
- end
87
- end
88
- alias_method :all, :settings
89
- alias_method :[], :settings
72
+ # Parse configuration parameters in yaml format.
73
+
74
+ def parse(options)
75
+ temp = YAML::load(options)
76
+ options = {}
77
+ temp.each do |k, v|
78
+ begin
79
+ options[constant(k.gsub(/\./, '::').to_sym)] = v
80
+ rescue Object
81
+ options[k] = v
82
+ end
83
+ end
84
+ setup(options)
85
+ end
86
+
87
+ # Load and parse an external yaml configuration file.
88
+
89
+ def load(filename)
90
+ parse(File.read(filename))
91
+ end
92
+
93
+ def add_setting(owner, name, options)
94
+ s = @@owners[owner] || {}
95
+ s[name] = Setting.new(owner, name, options)
96
+ @@owners[owner] = s
97
+ end
98
+
99
+ def settings(owner = nil)
100
+ if owner
101
+ @@owners[owner]
102
+ else
103
+ @@owners.values.inject([]) { |memo, obj| memo.concat(obj.values) }
104
+ end
105
+ end
106
+ alias_method :all, :settings
107
+ alias_method :[], :settings
90
108
 
91
- def method_missing(sym)
92
- if sym.to_s =~ /[A-Z]/ # facet's capitalized? is buggy at the moment.
93
- Flexob.new(self[constant(sym)])
94
- end
95
- end
96
- end
97
-
109
+ def method_missing(sym)
110
+ if sym.to_s =~ /[A-Z]/ # facet's capitalized? is buggy at the moment.
111
+ Flexob.new(self[constant(sym)])
112
+ end
113
+ end
114
+ end
115
+
98
116
  end
99
117
 
100
118
  # Alias for the Configuration class (shorter).
@@ -104,23 +122,23 @@ end
104
122
 
105
123
  class Module
106
124
 
107
- # Defines a configuration setting.
108
- #--
109
- # TODO: implement with annotations.
110
- #++
111
-
112
- def setting(sym, options = {})
113
- Configuration.add_setting(self, sym, options)
114
- module_eval %{
115
- mattr_accessor sym, options[:default]
116
-
125
+ # Defines a configuration setting.
126
+ #--
127
+ # TODO: implement with annotations.
128
+ #++
129
+
130
+ def setting(sym, options = {})
131
+ Configuration.add_setting(self, sym, options)
132
+ module_eval %{
133
+ mattr_accessor sym, options[:default]
134
+
117
135
  def self.#{sym.id2name}=(obj)
118
136
  @@#{sym.id2name} = obj
119
137
  Configuration[#{self}][:#{sym}].value = obj
120
138
  end
121
- }
122
- end
123
-
139
+ }
140
+ end
141
+
124
142
  end
125
143
 
126
- # * George Moschovitis <gm@navel.gr>
144
+ # * George Moschovitis <gm@navel.gr>