utilrb 2.0.0 → 2.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.
@@ -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