fxri 0.1.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.
@@ -0,0 +1,192 @@
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
2
+ require 'set'
3
+
4
+ # Packet_List is a more convenient wrapper for FXIconList. This class has to be used
5
+ # in combination with Packet_Item.
6
+ class Packet_List < FXIconList
7
+ include Responder
8
+
9
+ # Create a new Packet_List. All parameters are passed to the parental constructor FXIconList.
10
+ def initialize(data, *args)
11
+ @data = data
12
+ @sort_mutex = Mutex.new
13
+ @sort_thread = nil
14
+ if FOXVERSION=="1.0"
15
+ def getItem(num)
16
+ retrieveItem(num)
17
+ end
18
+ end
19
+
20
+ @header_item_index = 0
21
+ @reversed = false
22
+ @conversions = Array.new
23
+ @items = Set.new
24
+ super(*args)
25
+
26
+ header.connect(SEL_COMMAND) do |sender, sel, item_number|
27
+ on_cmd_header(item_number)
28
+ end
29
+
30
+
31
+ # HACK: only works when one header is there.
32
+ self.connect(SEL_CONFIGURE) do |sender, sel, data|
33
+ update_header_width
34
+ end
35
+ end
36
+
37
+ def create
38
+ super
39
+ recalc
40
+ end
41
+
42
+ # HACK: only works when one header is there.
43
+ def update_header_width
44
+ header.setItemSize(0, width-verticalScrollBar.width)
45
+ recalc
46
+ end
47
+
48
+
49
+ # Called whenever a header is clicked
50
+ def on_cmd_header(header_item_index)
51
+ @data.gui_mutex.synchronize do
52
+ header.setArrowDir(@header_item_index, MAYBE)
53
+ if @header_item_index == header_item_index
54
+ @reversed = !@reversed
55
+ else
56
+ @reversed = false
57
+ end
58
+ @header_item_index = header_item_index
59
+ header.setArrowDir(@header_item_index, @reversed)
60
+ sortItems
61
+ end
62
+ # sort array
63
+ @data.items.sort! do |a, b|
64
+ cmp = a.sortable(header_item_index) <=> b.sortable(header_item_index)
65
+ if @reversed
66
+ -cmp
67
+ else
68
+ cmp
69
+ end
70
+ end
71
+ return 0
72
+ end
73
+
74
+ def sortItems
75
+ @items.each do |item|
76
+ item.update_sort_key
77
+ end
78
+ super
79
+ end
80
+
81
+ # Check if the search order is reversed (happens when clicking on the same header twice)
82
+ def reversed?
83
+ @reversed
84
+ end
85
+
86
+ # Get index of the header that should be used for sorting
87
+ def sort_index
88
+ @header_item_index
89
+ end
90
+
91
+ # Add a new header. The block that you need to specify is used to convert a string of this
92
+ # column into something that can be used for sorting. The yielded parameter item_colum_text
93
+ # is the text of one item of this column.
94
+ def add_header(text, width, &conversion) # :yields: item_column_text
95
+ appendHeader(text, nil, width)
96
+ header.setArrowDir(0, false) if @conversions.empty?
97
+ @conversions.push conversion
98
+ end
99
+
100
+ # Create a new Packet_Item. After the icon, you can specify the text for each of the columns.
101
+ # Here is an example:
102
+ # list.create_item(my_icon, "Martin", "Ankerl", "2005")
103
+ def create_item(icon, *args)
104
+ Packet_Item.new(self, icon, *args)
105
+ end
106
+
107
+ # Add a new Packet_Item to this list.Called from within Packet_Item during Packet_Item#parent=
108
+ def add_item(item)
109
+ @items.add item
110
+ appendItem(item.fox_item)
111
+ item
112
+ end
113
+
114
+ # Remove the given Packet_Item from the list. This is slow, because
115
+ # the item has to be searched with a linear search. To remove all items
116
+ # use #clear.
117
+ def remove_item(item)
118
+ i = 0
119
+ @items.delete item
120
+ fox_item = item.fox_item
121
+ i += 1 while i < numItems && fox_item != getItem(i)
122
+ removeItem(i) if i < numItems
123
+ item
124
+ end
125
+
126
+ def appendItem(*args)
127
+ $fx_icon_item_remove_mutex.synchronize do
128
+ #puts "appendItem"
129
+ super
130
+ end
131
+ end
132
+
133
+ # Before actually deleting, the item has to be marked as deleted to prevent
134
+ # drawing afterwards.
135
+ def removeItem(*args)
136
+ $fx_icon_item_remove_mutex.synchronize do
137
+ #puts "removeitem"
138
+ # at first, mark item as deleted to prevent drawing afterwards
139
+ getItem(args[0]).deleted
140
+ # do the evil delete
141
+ super
142
+ end
143
+ end
144
+
145
+ # Remove all items, but do this within the mutex to be sure everything goes ok.
146
+ def clearItems(*args)
147
+ $fx_icon_item_remove_mutex.synchronize do
148
+ #puts "clearitems"
149
+ super
150
+ end
151
+ end
152
+
153
+ # This may be called when the item is currently beeing deleted.
154
+ # this method works only before or after the delete, therefore
155
+ # the mutex is necessary.
156
+ def getContentWidth(*args)
157
+ $fx_icon_item_remove_mutex.synchronize do
158
+ #puts "contentwidth"
159
+ super
160
+ end
161
+ end
162
+
163
+ # This may be called when the item is currently beeing deleted.
164
+ # this method works only before or after the delete, therefore
165
+ # the mutex is necessary.
166
+ def getContentHeight(*args)
167
+ $fx_icon_item_remove_mutex.synchronize do
168
+ #puts "contentheight"
169
+ super
170
+ end
171
+ end
172
+
173
+ # Removes all items from the list.
174
+ def clear
175
+ @items.each { |item| item.clear }
176
+ @items.clear
177
+ # todo: mutex!?
178
+ clearItems
179
+ end
180
+
181
+ # use in combination with Packet_Item#show
182
+ def dirty_clear
183
+ clearItems
184
+ @items.clear
185
+ end
186
+
187
+ # Get the sort for a given header index. The sort function has been supplied
188
+ # when calling #new. This is used from Packet_Item.
189
+ def sort_function(header_item_index)
190
+ @conversions[header_item_index]
191
+ end
192
+ end
@@ -0,0 +1,233 @@
1
+ # Author:: Martin Ankerl (mailto:martin.ankerl@gmail.com)
2
+
3
+ # Recursive_Open_Struct provides a convenient interface to a hierarchy of configuration
4
+ # parameters. You do not need to define the accessors, they are created automatically
5
+ # on demand.
6
+ #
7
+ # Have a look at this example:
8
+ #
9
+ # ac = Recursive_Open_Struct.new
10
+ # ac.window.name = "SuperDuper"
11
+ # ac.app.version = "2.1.3"
12
+ # ac.this.is.automatically.created = "blabla"
13
+ #
14
+ # After you have created all of your configuration parameters, to prevent
15
+ # typos when using the parameters, the structure can be closed:
16
+ #
17
+ # ac.close
18
+ #
19
+ # After closing,
20
+ #
21
+ # ac.widnow.name = "UberSuperDuper"
22
+ #
23
+ # You get the usual NoMethodError, because 'widnow' does not exist.
24
+ #
25
+ class Recursive_Open_Struct
26
+ # Create a new Recursive_Open_Struct.
27
+ def initialize
28
+ @methods = Hash.new
29
+ @open = true
30
+ end
31
+
32
+ # automatically add parameters
33
+ def method_missing(method, *params) # :nodoc:
34
+ # setting or getting?
35
+ is_setting = !params.empty?
36
+
37
+ key = method.id2name
38
+ # remove trailing =
39
+ key.chop! if is_setting
40
+
41
+ # if structure is closed, disable hierarchy creation
42
+ super unless @methods.has_key?(key) || @open
43
+
44
+ if is_setting
45
+ # assigning a new value
46
+ if @methods[key].class == Recursive_Open_Struct
47
+ raise TypeError, "overwriting previously created hierarchy entry '#{key}' not allowed", caller(1)
48
+ end
49
+ @methods[key] = *params
50
+ else
51
+ # no param: create new Recursive_Open_Struct object, if nothing is set.
52
+ unless @methods.has_key?(key)
53
+ @methods[key] = Recursive_Open_Struct.new
54
+ end
55
+ end
56
+ @methods[key]
57
+ end
58
+
59
+ # An alternative way to access the value of an attribute
60
+ # s = Recursive_Open_Struct.new
61
+ # s.name = "Hugo"
62
+ # s["name"] # "Hugo"
63
+ def [](key)
64
+ @methods[key]
65
+ end
66
+
67
+ # An alternative way to set the value of an attribute
68
+ # s = Recursive_Open_Struct.new
69
+ # s["name"] = "Hugo"
70
+ # s.name # "Hugo"
71
+ def []=(key, value)
72
+ self.send((key+"=").to_sym, value)
73
+ end
74
+
75
+ # call-seq:
76
+ # attrs() -> an_array
77
+ #
78
+ # Return a sorted array of attribute names, similar to #methods.
79
+ #
80
+ # s = Recursive_Open_Struct.new
81
+ # s.name = "martinus"
82
+ # s.age = 25
83
+ # s.attrs # returns ["age", "name"]
84
+ def attrs
85
+ @methods.keys.sort
86
+ end
87
+
88
+ # After calling #close, no further modification of the configuration hierarchy
89
+ # is allowed. This is not as strict as #freeze, because you are still allowed
90
+ # to modify data.
91
+ #
92
+ # s = Recursive_Open_Struct.new
93
+ # s.name = "Hugo"
94
+ # s.close
95
+ # s.name = "martinus" # does still work
96
+ # s.age = 25 # raises NoMethodError
97
+ def close
98
+ do_set_open_status(false)
99
+ end
100
+
101
+ # Reopens a Recursive_Open_Struct which was closed with #close earlier.
102
+ # After this call, it is possible to modify the structure again.
103
+ def re_open
104
+ do_set_open_status(true)
105
+ end
106
+
107
+ # call-seq:
108
+ # open?() -> boolean
109
+ #
110
+ # Return whether the structure is still open or not.
111
+ #
112
+ # s = Recursive_Open_Struct.new
113
+ # s.open? # returns true
114
+ # s.close
115
+ # s.open? # returns false
116
+ def open?
117
+ @open
118
+ end
119
+
120
+ # call-seq:
121
+ # each() { |elem| ... }
122
+ #
123
+ # Iterates through all elements of the Recursive_Open_Struct in alphabetic order.
124
+ def each
125
+ attrs.each do |attr|
126
+ yield @methods[attr]
127
+ end
128
+ end
129
+
130
+ protected
131
+
132
+ def do_set_open_status(status)
133
+ @methods.each_value do |val|
134
+ val.do_set_open_status(status) if val.class == Recursive_Open_Struct
135
+ end
136
+ @open = status
137
+ end
138
+ end
139
+
140
+ if __FILE__ == $0
141
+ require 'test/unit'
142
+
143
+ class TestRecursiveOpenStruct < Test::Unit::TestCase
144
+ def setup
145
+ @s = Recursive_Open_Struct.new
146
+ end
147
+
148
+ def setAndAssertValue(val)
149
+ @s.test = val
150
+ assert_equal(val, @s.test)
151
+ @s.close
152
+ assert_equal(val, @s.test)
153
+ @s.test = "asdf"
154
+ assert_equal("asdf", @s.test)
155
+ end
156
+
157
+ def testSetNil
158
+ setAndAssertValue(nil)
159
+ end
160
+
161
+ def testSimple
162
+ @s.test = "xx"
163
+ @s.close
164
+ assert_equal("xx", @s.test)
165
+ end
166
+
167
+ def testSetFalse
168
+ setAndAssertValue(false)
169
+ end
170
+
171
+ def testSetStr
172
+ setAndAssertValue("topfen")
173
+ end
174
+
175
+ def testSetClass
176
+ setAndAssertValue(String)
177
+ end
178
+
179
+ def testSetTrue
180
+ setAndAssertValue(true)
181
+ end
182
+
183
+ def testSet0
184
+ setAndAssertValue(0)
185
+ end
186
+
187
+ def testRaiseTypeError
188
+ @s.a.b = 1
189
+ assert_raise(TypeError) do
190
+ @s.a = 3
191
+ end
192
+ end
193
+
194
+ def testAttrs
195
+ assert_equal([], @s.attrs)
196
+ @s.b = "x"
197
+ @s.a = "a"
198
+ assert_equal(["a", "b"], @s.attrs)
199
+ end
200
+
201
+ def testRecursive
202
+ @s.a.b = 1
203
+ @s.a.c = 2
204
+ assert_equal(["a"], @s.attrs)
205
+ end
206
+
207
+ def testStrange
208
+ @s.a
209
+ assert_equal(["a"], @s.attrs)
210
+ assert_equal(Recursive_Open_Struct, @s.a.class)
211
+ @s.a.x = "asfd"
212
+ assert_equal("asfd", @s.a.x)
213
+ end
214
+
215
+ def testKlammer
216
+ @s.a = "asdf"
217
+ assert_equal("asdf", @s["a"])
218
+ @s.b_x = "hog"
219
+ assert_equal("hog", @s["b_x"])
220
+ @s.c.b.a = 1234
221
+ assert_equal(1234, @s["c"]["b"]["a"])
222
+ end
223
+
224
+ def testDeep
225
+ @s.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z = false
226
+ @s.close
227
+ assert_raise(NoMethodError) do
228
+ @s.blub = "hellow"
229
+ end
230
+ assert_equal(false, @s.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z)
231
+ end
232
+ end
233
+ end
data/lib/RiManager.rb ADDED
@@ -0,0 +1,155 @@
1
+ require "yaml"
2
+ require 'rdoc/ri/ri_driver'
3
+ require 'pp'
4
+
5
+ class NameDescriptor
6
+ CLASS = 0
7
+ INSTANCE_METHOD = 1
8
+ CLASS_METHOD = 2
9
+ def type
10
+ @method_name ||= false
11
+ @is_class_method ||= false
12
+ if @method_name
13
+ if @is_class_method
14
+ CLASS_METHOD
15
+ else
16
+ INSTANCE_METHOD
17
+ end
18
+ else
19
+ CLASS
20
+ end
21
+ end
22
+
23
+ def to_s
24
+ str = ""
25
+ str << @class_names.join("::")
26
+ if @method_name && str != ""
27
+ str << (@is_class_method ? "::" : "#")
28
+ end
29
+ str << @method_name if @method_name
30
+ str
31
+ end
32
+ end
33
+
34
+ # This basically is a stripped down version of RiDriver.
35
+ # I cannot use RiDriver directly, because I need to set the driver.
36
+ class RiManager
37
+ def initialize(display, path = RI::Paths::PATH)
38
+ @reader = RI::RiReader.new(RI::RiCache.new(RI::Paths::PATH))
39
+ @display = display
40
+ @display.reader = @reader
41
+ # prepare all names
42
+ @all_names = prepare_all_names
43
+ end
44
+
45
+ def prepare_all_names
46
+ names = Array.new
47
+ @reader.all_names.each do |name|
48
+ begin
49
+ names.push NameDescriptor.new(name)
50
+ rescue RiError => e
51
+ # silently ignore errors
52
+ end
53
+ end
54
+ names
55
+ end
56
+
57
+ def check_names
58
+ @reader.all_names.each do |name|
59
+ begin
60
+ if (NameDescriptor.new(name).to_s != name)
61
+ p [name, NameDescriptor.new(name).to_s, NameDescriptor.new(name)]
62
+ end
63
+ rescue RiError => e
64
+ puts e
65
+ end
66
+ end
67
+ end
68
+
69
+ # Returns all fully names as name descriptors
70
+ def all_names
71
+ @all_names
72
+ end
73
+
74
+ # Searches for the description of a name and shows it using +display+.
75
+ def show(name_descriptor, width)
76
+ @display.width = width
77
+ # narrow down namespace
78
+ namespace = @reader.top_level_namespace
79
+ name_descriptor.class_names.each do |classname|
80
+ namespace = @reader.lookup_namespace_in(classname, namespace)
81
+ if namespace.empty?
82
+ raise RiError.new("Nothing known about #{name_descriptor}")
83
+ end
84
+ end
85
+
86
+ # At this point, if we have multiple possible namespaces, but one
87
+ # is an exact match for our requested class, prune down to just it
88
+ # PS: this comment is shamlessly stolen from ri_driver.rb
89
+ entries = namespace.find_all {|m| m.full_name == name_descriptor.full_class_name}
90
+ namespace = entries if entries.size == 1
91
+
92
+ if name_descriptor.method_name
93
+ methods = @reader.find_methods(name_descriptor.method_name, name_descriptor.is_class_method, namespace)
94
+ report_method_stuff(name_descriptor.method_name, methods)
95
+ else
96
+ report_class_stuff(namespace)
97
+ end
98
+ end
99
+
100
+ def report_class_stuff(namespace)
101
+ raise RiError.new("namespace") unless namespace.size==1
102
+ @display.display_class_info @reader.get_class(namespace[0])
103
+ end
104
+
105
+ def report_method_stuff(requested_method_name, methods)
106
+ if methods.size == 1
107
+ method = @reader.get_method(methods[0])
108
+ @display.display_method_info(method)
109
+ else
110
+ entries = methods.find_all {|m| m.name == requested_method_name}
111
+ if entries.size == 1
112
+ method = @reader.get_method(entries[0])
113
+ @display.display_method_info(method)
114
+ else
115
+ puts methods.map {|m| m.full_name}.join(", ")
116
+ end
117
+ end
118
+ =begin
119
+
120
+ method = if (methods.size == 1)
121
+ @reader.get_method(methods[0])
122
+ else
123
+ entries = methods.find_all {|m| m.name == requested_method_name}
124
+ entries.size
125
+ # there really should be just *one* method that matches.
126
+ raise RiError.new("got a strange method") unless entries.size == 1
127
+ @reader.get_method(entries[0])
128
+ end
129
+ @display.display_method_info(method)
130
+ =end
131
+ end
132
+ end
133
+
134
+ if __FILE__ == $0
135
+ display = Displayer.new
136
+ ri = RiManager.new(display)
137
+ ri.all_names.each do |name|
138
+ p [name.type, name.to_s] if name.type==0
139
+ end
140
+ end
141
+
142
+
143
+ =begin
144
+ # iterate through everything
145
+ reader.full_class_names.sort.each do |class_name|
146
+ classDesc = reader.find_class_by_name(class_name)
147
+
148
+ if class_name=="Integer"
149
+ pp classDesc.instance_methods
150
+ puts classDesc.to_yaml
151
+ #puts classDesc.methods
152
+ gets
153
+ end
154
+ end
155
+ =end