utilrb 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ class Logger
2
+ # Silences this logger for the duration of the block
3
+ def silent
4
+ current_level, self.level = self.level, Logger::FATAL + 1
5
+ yield
6
+ ensure
7
+ self.level = current_level
8
+ end
9
+ end
10
+
@@ -0,0 +1,341 @@
1
+ require 'utilrb/object/attribute'
2
+ require 'utilrb/object/singleton_class'
3
+ require 'utilrb/enumerable/uniq'
4
+ require 'utilrb/module/include'
5
+
6
+ module Utilrb
7
+ module Models
8
+ # Helper method for inherited_enumerable
9
+ #
10
+ # It is called in the context of the singleton class of the module/class on
11
+ # which inherited_enumerable is called
12
+ def define_inherited_enumerable(name, attribute_name = name, options = Hash.new, &init) # :nodoc:
13
+ # Set up the attribute accessor
14
+ attribute(attribute_name, &init)
15
+ class_eval { private "#{attribute_name}=" }
16
+
17
+ promote = method_defined?("promote_#{name}")
18
+ options[:enum_with] ||= :each
19
+
20
+ class_eval <<-EOF, __FILE__, __LINE__+1
21
+ def all_#{name}; each_#{name}.to_a end
22
+ def self_#{name}; @#{attribute_name} end
23
+ EOF
24
+
25
+ if options[:map]
26
+ class_eval <<-EOF, __FILE__, __LINE__+1
27
+ def find_#{name}(key)
28
+ raise ArgumentError, "nil cannot be used as a key in find_#{name}" if !key
29
+ each_#{name}(key, true) do |value|
30
+ return value
31
+ end
32
+ nil
33
+ end
34
+ def has_#{name}?(key)
35
+ ancestors = self.ancestors
36
+ if ancestors.first != self
37
+ ancestors.unshift self
38
+ end
39
+ for klass in ancestors
40
+ if klass.instance_variable_defined?(:@#{attribute_name})
41
+ return true if klass.#{attribute_name}.has_key?(key)
42
+ end
43
+ end
44
+ false
45
+ end
46
+ EOF
47
+ end
48
+
49
+ class_eval <<-EOF, __FILE__, __LINE__+1
50
+ def clear_#{attribute_name}
51
+ #{attribute_name}.clear
52
+ for klass in ancestors
53
+ if klass.instance_variable_defined?(:@#{attribute_name})
54
+ klass.#{attribute_name}.clear
55
+ end
56
+ end
57
+ end
58
+ EOF
59
+
60
+ if !promote
61
+ if options[:map]
62
+ define_inherited_enumerable_map_without_promotion(name, attribute_name, options)
63
+ else
64
+ define_inherited_enumerable_nomap_without_promotion(name, attribute_name, options)
65
+ end
66
+ else
67
+ if options[:map]
68
+ define_inherited_enumerable_map_with_promotion(name, attribute_name, options)
69
+ else
70
+ define_inherited_enumerable_nomap_with_promotion(name, attribute_name, options)
71
+ end
72
+ end
73
+ end
74
+
75
+ def define_inherited_enumerable_map_without_promotion(name, attribute_name, options)
76
+ class_eval <<-EOF, __FILE__, __LINE__+1
77
+ def each_#{name}(key = nil, uniq = true)
78
+ if !block_given?
79
+ return enum_for(:each_#{name}, key, uniq)
80
+ end
81
+
82
+ ancestors = self.ancestors
83
+ if ancestors.first != self
84
+ ancestors.unshift self
85
+ end
86
+ if key
87
+ for klass in ancestors
88
+ if klass.instance_variable_defined?(:@#{attribute_name})
89
+ if klass.#{attribute_name}.has_key?(key)
90
+ yield(klass.#{attribute_name}[key])
91
+ return self if uniq
92
+ end
93
+ end
94
+ end
95
+ elsif !uniq
96
+ for klass in ancestors
97
+ if klass.instance_variable_defined?(:@#{attribute_name})
98
+ klass.#{attribute_name}.#{options[:enum_with]} do |el|
99
+ yield(el)
100
+ end
101
+ end
102
+ end
103
+ else
104
+ seen = Set.new
105
+ for klass in ancestors
106
+ if klass.instance_variable_defined?(:@#{attribute_name})
107
+ klass.#{attribute_name}.#{options[:enum_with]} do |el|
108
+ unless seen.include?(el.first)
109
+ seen << el.first
110
+ yield(el)
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ end
117
+ self
118
+ end
119
+ EOF
120
+ end
121
+
122
+ def define_inherited_enumerable_nomap_without_promotion(name, attribute_name, options)
123
+ class_eval <<-EOF, __FILE__, __LINE__+1
124
+ def each_#{name}
125
+ if !block_given?
126
+ return enum_for(:each_#{name})
127
+ end
128
+
129
+ ancestors = self.ancestors
130
+ if ancestors.first != self
131
+ ancestors.unshift self
132
+ end
133
+ for klass in ancestors
134
+ if klass.instance_variable_defined?(:@#{attribute_name})
135
+ klass.#{attribute_name}.#{options[:enum_with]} { |el| yield(el) }
136
+ end
137
+ end
138
+ self
139
+ end
140
+ EOF
141
+ end
142
+
143
+ def define_inherited_enumerable_map_with_promotion(name, attribute_name, options)
144
+ class_eval <<-EOF, __FILE__, __LINE__+1
145
+ def each_#{name}(key = nil, uniq = true)
146
+ if !block_given?
147
+ return enum_for(:each_#{name}, key, uniq)
148
+ end
149
+
150
+ ancestors = self.ancestors
151
+ if ancestors.first != self
152
+ ancestors.unshift self
153
+ end
154
+ if key
155
+ promotions = []
156
+ for klass in ancestors
157
+ if klass.instance_variable_defined?(:@#{attribute_name})
158
+ if klass.#{attribute_name}.has_key?(key)
159
+ value = klass.#{attribute_name}[key]
160
+ for p in promotions
161
+ value = p.promote_#{name}(key, value)
162
+ end
163
+ yield(value)
164
+ return self if uniq
165
+ end
166
+ end
167
+ promotions.unshift(klass) if klass.respond_to?("promote_#{name}")
168
+ end
169
+ elsif !uniq
170
+ promotions = []
171
+ for klass in ancestors
172
+ if klass.instance_variable_defined?(:@#{attribute_name})
173
+ klass.#{attribute_name}.#{options[:enum_with]} do |key, value|
174
+ for p in promotions
175
+ value = p.promote_#{name}(key, value)
176
+ end
177
+ yield(key, value)
178
+ end
179
+ end
180
+ promotions.unshift(klass) if klass.respond_to?("promote_#{name}")
181
+ end
182
+ else
183
+ seen = Set.new
184
+ promotions = []
185
+ for klass in ancestors
186
+ if klass.instance_variable_defined?(:@#{attribute_name})
187
+ klass.#{attribute_name}.#{options[:enum_with]} do |key, value|
188
+ unless seen.include?(key)
189
+ for p in promotions
190
+ value = p.promote_#{name}(key, value)
191
+ end
192
+ seen << key
193
+ yield(key, value)
194
+ end
195
+ end
196
+ end
197
+ promotions.unshift(klass) if klass.respond_to?("promote_#{name}")
198
+ end
199
+ end
200
+ self
201
+ end
202
+ EOF
203
+ end
204
+
205
+ def define_inherited_enumerable_nomap_with_promotion(name, attribute_name, options)
206
+ class_eval <<-EOF, __FILE__, __LINE__+1
207
+ def each_#{name}
208
+ if !block_given?
209
+ return enum_for(:each_#{name})
210
+ end
211
+
212
+ ancestors = self.ancestors
213
+ if ancestors.first != self
214
+ ancestors.unshift self
215
+ end
216
+ promotions = []
217
+ for klass in ancestors
218
+ if klass.instance_variable_defined?(:@#{attribute_name})
219
+ klass.#{attribute_name}.#{options[:enum_with]} do |value|
220
+ for p in promotions
221
+ value = p.promote_#{name}(value)
222
+ end
223
+ yield(value)
224
+ end
225
+ end
226
+ promotions.unshift(klass) if klass.respond_to?("promote_#{name}")
227
+ end
228
+ self
229
+ end
230
+ EOF
231
+ end
232
+
233
+ # Defines an attribute as being enumerable in the class instance and in the
234
+ # whole class inheritance hierarchy. More specifically, it defines a
235
+ # <tt>each_#{name}(&iterator)</tt> instance method and a <tt>each_#{name}(&iterator)</tt>
236
+ # class method which iterates (in order) on
237
+ # - the instance #{name} attribute
238
+ # - the singleton class #{name} attribute
239
+ # - the class #{name} attribute
240
+ # - the superclass #{name} attribute
241
+ # - the superclass' superclass #{name} attribute
242
+ # ...
243
+ #
244
+ # This method can be used on modules, in which case the module is used as if
245
+ # it was part of the inheritance hierarchy.
246
+ #
247
+ # The +name+ option defines the enumeration method name (+value+ will
248
+ # define a +each_value+ method). +attribute_name+ defines the attribute
249
+ # name. +init+ is a block called to initialize the attribute.
250
+ # Valid options in +options+ are:
251
+ # map::
252
+ # If true, the attribute should respond to +[]+. In that case, the
253
+ # enumeration method is each_value(key = nil, uniq = false) If +key+ is
254
+ # given, we iterate on the values given by <tt>attribute[key]</tt>. If
255
+ # +uniq+ is true, the enumeration will yield at most one value for each
256
+ # +key+ found (so, if both +key+ and +uniq+ are given, the enumeration
257
+ # yields at most one value). See the examples below
258
+ # enum_with:: the enumeration method of the enumerable, if it is not +each+
259
+ #
260
+ # === Example
261
+ # Let's define some classes and look at the ancestor chain
262
+ #
263
+ # class A; end
264
+ # module M; end
265
+ # class B < A; include M end
266
+ # A.ancestors # => [A, Object, Kernel]
267
+ # B.ancestors # => [B, M, A, Object, Kernel]
268
+ #
269
+ # ==== Attributes for which 'map' is not set
270
+ #
271
+ # class A
272
+ # inherited_enumerable("value", "values") do
273
+ # Array.new
274
+ # end
275
+ # end
276
+ # module M
277
+ # inherited_enumerable("mod") do
278
+ # Array.new
279
+ # end
280
+ # end
281
+ #
282
+ # A.values << 1 # => [1]
283
+ # B.values << 2 # => [2]
284
+ # M.mod << 1 # => [1]
285
+ # b = B.new
286
+ # class << b
287
+ # self.values << 3 # => [3]
288
+ # self.mod << 4 # => [4]
289
+ # end
290
+ # M.mod << 2 # => [1, 2]
291
+ #
292
+ # A.enum_for(:each_value).to_a # => [1]
293
+ # B.enum_for(:each_value).to_a # => [2, 1]
294
+ # b.singleton_class.enum_for(:each_value).to_a # => [3, 2, 1]
295
+ # b.singleton_class.enum_for(:each_mod).to_a # => [4, 1, 2]
296
+ #
297
+ # ==== Attributes for which 'map' is set
298
+ #
299
+ # class A
300
+ # inherited_enumerable("mapped", "map", :map => true) do
301
+ # Hash.new { |h, k| h[k] = Array.new }
302
+ # end
303
+ # end
304
+ #
305
+ # A.map['name'] = 'A' # => "A"
306
+ # A.map['universe'] = 42
307
+ # B.map['name'] = 'B' # => "B"
308
+ # B.map['half_of_it'] = 21
309
+ #
310
+ # Let's see what happens if we don't specify the key option.
311
+ # A.enum_for(:each_mapped).to_a # => [["name", "A"], ["universe", 42]]
312
+ # If the +uniq+ option is set (the default), we see only B's value for 'name'
313
+ # B.enum_for(:each_mapped).to_a # => [["half_of_it", 21], ["name", "B"], ["universe", 42]]
314
+ # If the +uniq+ option is not set, we see both values for 'name'. Note that
315
+ # since 'map' is a Hash, the order of keys in one class is not guaranteed.
316
+ # Nonetheless, we have the guarantee that values from B appear before
317
+ # those from A
318
+ # B.enum_for(:each_mapped, nil, false).to_a # => [["half_of_it", 21], ["name", "B"], ["name", "A"], ["universe", 42]]
319
+ #
320
+ #
321
+ # Now, let's see how 'key' behaves
322
+ # A.enum_for(:each_mapped, 'name').to_a # => ["A"]
323
+ # B.enum_for(:each_mapped, 'name').to_a # => ["B"]
324
+ # B.enum_for(:each_mapped, 'name', false).to_a # => ["B", "A"]
325
+ #
326
+ def inherited_enumerable(name, attribute_name = name, options = Hash.new, &init)
327
+ singleton_class.class_eval { define_inherited_enumerable(name, attribute_name, options, &init) }
328
+
329
+ if is_a?(Module) && !is_a?(Class)
330
+ unless const_defined_here?(:ClassExtension)
331
+ const_set(:ClassExtension, Module.new)
332
+ end
333
+ class_extension = const_get(:ClassExtension)
334
+ class_extension.class_eval do
335
+ define_inherited_enumerable(name, attribute_name, options, &init)
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end
341
+
@@ -0,0 +1,115 @@
1
+ require 'facets/kernel/call_stack'
2
+ require 'utilrb/object/attribute'
3
+ require 'utilrb/module/attr_predicate'
4
+ module Utilrb
5
+ module Models
6
+
7
+ # Handling of registration of model hierarchies
8
+ #
9
+ # It depends on the mixed-in object to provide a #supermodel method that
10
+ # returns the model that is parent of +self+
11
+ module Registration
12
+ # The place where this model got defined in the source code
13
+ # The tuple is (file,lineno,method), and can be obtained with
14
+ # facet's #call_stack
15
+ # @return [Array<(String,Integer,Symbol)>]
16
+ attr_accessor :definition_location
17
+
18
+ # Tells {#clear_submodels} whether this model should be removed from
19
+ # the model set or not. The default is false (it should be removed)
20
+ #
21
+ # @return [Boolean]
22
+ attr_predicate :permanent_model?, true
23
+
24
+ # [ValueSet] the set of models that are children of this one
25
+ attribute(:submodels) { ValueSet.new }
26
+
27
+ # Returns the model that is parent of this one
28
+ #
29
+ # The default implementation returns superclass if it is extended by
30
+ # this Registration module, and nil otherwise
31
+ def supermodel
32
+ if superclass.respond_to?(:register_submodel)
33
+ superclass
34
+ end
35
+ end
36
+
37
+ # Call to register a model that is a submodel of +self+
38
+ def register_submodel(klass)
39
+ if !klass.definition_location
40
+ klass.definition_location = call_stack
41
+ end
42
+
43
+ if klass.name && !klass.permanent_model?
44
+ begin
45
+ if constant("::#{klass.name}") == klass
46
+ klass.permanent_model = true
47
+ end
48
+ rescue NameError
49
+ end
50
+ end
51
+
52
+ submodels << klass
53
+ if m = supermodel
54
+ m.register_submodel(klass)
55
+ end
56
+ end
57
+
58
+ # Enumerates all models that are submodels of this class
59
+ def each_submodel
60
+ return enum_for(:each_submodel) if !block_given?
61
+ submodels.each do |obj|
62
+ yield(obj)
63
+ end
64
+ end
65
+
66
+ # Clears all registered submodels
67
+ def clear_submodels
68
+ children = self.submodels.find_all { |m| !m.permanent_model? }
69
+ if !deregister_submodels(children)
70
+ return
71
+ end
72
+
73
+ # This contains the permanent submodels
74
+ #
75
+ # We can call #clear_submodels while iterating here as it is a
76
+ # constraint that all models in #submodels are permanent (and
77
+ # will therefore not be removed)
78
+ submodels.each { |m| m.clear_submodels }
79
+ # And this the non-permanent ones
80
+ children.each { |m| m.clear_submodels }
81
+ true
82
+ end
83
+
84
+ # Deregisters a set of submodels on this model and all its
85
+ # supermodels
86
+ #
87
+ # This is usually not called directly. Use #clear_submodels instead
88
+ #
89
+ # @param [ValueSet] set the set of submodels to remove
90
+ def deregister_submodels(set)
91
+ current_size = submodels.size
92
+ submodels.difference!(set.to_value_set)
93
+ if (submodels.size != current_size)
94
+ if m = supermodel
95
+ m.deregister_submodels(set)
96
+ end
97
+ true
98
+ else false
99
+ end
100
+ end
101
+
102
+ # Registers submodels when a subclass is created (when models are
103
+ # represented as classes)
104
+ def inherited(subclass)
105
+ subclass.definition_location = call_stack
106
+ super
107
+ register_submodel(subclass)
108
+ subclass.permanent_model = true
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+
@@ -0,0 +1,20 @@
1
+ require 'pathname'
2
+ class Pathname
3
+ # Returns the path object that is the first parent of self matching the
4
+ # given predicate
5
+ #
6
+ # @yieldparam [Pathname] path the path object that should be tested
7
+ # @yieldreturn [Boolean] true if this is the path you are looking for, and
8
+ # false otherwise
9
+ # @return [Pathname,nil] the matching path or nil if none could be found
10
+ def find_matching_parent
11
+ # Look for a bundle in the parents of Dir.pwd
12
+ curdir = self
13
+ while !curdir.root? && !yield(curdir)
14
+ curdir = curdir.parent
15
+ end
16
+ if !curdir.root?
17
+ curdir
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
3
+
@@ -0,0 +1,18 @@
1
+ require 'set'
2
+ module Qt
3
+ class MimeData
4
+ # prevents deleting the object until it get finalized by c++
5
+ @@saved_values = Hash.new
6
+ def initialize
7
+ super
8
+ ObjectSpace.define_finalizer self, MimeData::ruby_finalizer
9
+ @@saved_values[self.object_id] ||= Set.new
10
+ @@saved_values[self.object_id] << self
11
+ end
12
+
13
+ def self.ruby_finalizer
14
+ lambda { |id| @@saved_values.delete(id) }
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,30 @@
1
+ require 'set'
2
+ module Qt
3
+ class Variant
4
+ # This is a mapping from a QVariant object_id to the object it is
5
+ # supposed to hold. An entry gets removed as soon as the QVariant is
6
+ # finalized
7
+ @@saved_values = Hash.new
8
+ def self.from_ruby(obj, lifetime_object = nil)
9
+ variant = Qt::Variant.new("__##{obj.object_id}#__")
10
+ lifetime_object ||= variant
11
+ ObjectSpace.define_finalizer lifetime_object, from_ruby_finalizer
12
+ @@saved_values[lifetime_object.object_id] ||= Set.new
13
+ @@saved_values[lifetime_object.object_id] << obj
14
+ variant
15
+ end
16
+
17
+ def self.from_ruby_finalizer
18
+ lambda { |variant_id| @@saved_values.delete(variant_id) }
19
+ end
20
+
21
+ def to_ruby
22
+ raise "QVariant is not storing an Object ID"if (value =~ /__#(\d*)#__/) != 0
23
+ ObjectSpace._id2ref(Integer($1))
24
+ end
25
+
26
+ def to_ruby?
27
+ (value =~ /__#(\d*)#__/) == 0
28
+ end
29
+ end
30
+ end