@@ -35,6 +35,78 @@ module Vips
35
35
36
36
attach_function :vips_operation_get_flags , [ :pointer ] , :int
37
37
38
+ # Introspect a vips operation and return a large structure containing
39
+ # everything we know about it. This is used for doc generation as well as
40
+ # call.
41
+ class Introspect
42
+ attr_reader :name , :description , :flags , :args , :required_input ,
43
+ :optional_input , :required_output , :optional_output
44
+
45
+ @@introspect_cache = { }
46
+
47
+ def initialize name
48
+ op = Operation . new name
49
+
50
+ @name = name
51
+ @description = Vips ::vips_object_get_description op
52
+ @flags = op . get_flags
53
+ @args = [ ]
54
+ @required_input = [ ]
55
+ @optional_input = { }
56
+ @required_output = [ ]
57
+ @optional_output = { }
58
+
59
+ # find all the arguments the operator can take
60
+ op . argument_map do |pspec , argument_class , _argument_instance |
61
+ flags = argument_class [ :flags ]
62
+ if ( flags & ARGUMENT_CONSTRUCT ) != 0
63
+ # names can include - as punctuation, but we always use _ in
64
+ # Ruby
65
+ arg_name = pspec [ :name ] . tr ( "-" , "_" )
66
+ gtype = op . get_typeof arg_name
67
+ blurb = GObject ::g_param_spec_get_blurb pspec
68
+
69
+ @args << [ arg_name , flags , gtype , blurb ]
70
+ end
71
+ end
72
+
73
+ @args . each do |details |
74
+ arg_name , flags , gtype , blurb = details
75
+
76
+ next if ( flags & ARGUMENT_DEPRECATED ) != 0
77
+
78
+ if ( flags & ARGUMENT_INPUT ) != 0
79
+ if ( flags & ARGUMENT_REQUIRED ) != 0
80
+ @required_input << details
81
+ else
82
+ @optional_input [ arg_name ] = details
83
+ end
84
+ end
85
+
86
+ # MODIFY INPUT args count as OUTPUT as well
87
+ if ( flags & ARGUMENT_OUTPUT ) != 0 ||
88
+ ( ( flags & ARGUMENT_INPUT ) != 0 &&
89
+ ( flags & ARGUMENT_MODIFY ) != 0 )
90
+ if ( flags & ARGUMENT_REQUIRED ) != 0
91
+ @required_output << details
92
+ else
93
+ @optional_output [ arg_name ] = details
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ def self . get name
101
+ if ! @@introspect_cache . include? name
102
+ @@introspect_cache [ name ] = Introspect . new name
103
+ end
104
+
105
+ @@introspect_cache [ name ]
106
+ end
107
+
108
+ end
109
+
38
110
class Operation < Object
39
111
# the layout of the VipsOperation struct
40
112
module OperationLayout
@@ -87,24 +159,6 @@ def get_flags
87
159
Vips ::vips_operation_get_flags self
88
160
end
89
161
90
- # not quick! try to call this infrequently
91
- def get_construct_args
92
- args = [ ]
93
-
94
- argument_map do |pspec , argument_class , _argument_instance |
95
- flags = argument_class [ :flags ]
96
- if ( flags & ARGUMENT_CONSTRUCT ) != 0
97
- # names can include - as punctuation, but we always use _ in
98
- # Ruby
99
- name = pspec [ :name ] . tr ( "-" , "_" )
100
-
101
- args << [ name , flags ]
102
- end
103
- end
104
-
105
- return args
106
- end
107
-
108
162
# search array for the first element to match a predicate ...
109
163
# search inside subarrays and sub-hashes
110
164
def self . find_inside object , &block
@@ -135,9 +189,7 @@ def self.imageize match_image, value
135
189
136
190
# set an operation argument, expanding constants and copying images as
137
191
# required
138
- def set name , value , match_image = nil , flags = 0
139
- gtype = get_typeof name
140
-
192
+ def set name , value , match_image , flags , gtype
141
193
if gtype == IMAGE_TYPE
142
194
value = Operation ::imageize match_image , value
143
195
@@ -227,39 +279,10 @@ def self.call name, supplied, optional = {}, option_string = ""
227
279
"optional = #{ optional } , option_string = #{ option_string } "
228
280
}
229
281
230
- op = Operation . new name
231
-
232
- # find and classify all the arguments the operator can take
233
- args = op . get_construct_args
234
- required_input = [ ]
235
- optional_input = { }
236
- required_output = [ ]
237
- optional_output = { }
238
- args . each do |arg_name , flags |
239
- next if ( flags & ARGUMENT_DEPRECATED ) != 0
282
+ introspect = Introspect . get name
240
283
241
- if ( flags & ARGUMENT_INPUT ) != 0
242
- if ( flags & ARGUMENT_REQUIRED ) != 0
243
- required_input << [ arg_name , flags ]
244
- else
245
- optional_input [ arg_name ] = flags
246
- end
247
- end
248
-
249
- # MODIFY INPUT args count as OUTPUT as well
250
- if ( flags & ARGUMENT_OUTPUT ) != 0 ||
251
- ( ( flags & ARGUMENT_INPUT ) != 0 &&
252
- ( flags & ARGUMENT_MODIFY ) != 0 )
253
- if ( flags & ARGUMENT_REQUIRED ) != 0
254
- required_output << [ arg_name , flags ]
255
- else
256
- optional_output [ arg_name ] = flags
257
- end
258
- end
259
- end
284
+ op = Operation . new name
260
285
261
- # so we should have been supplied with n_required_input values, or
262
- # n_required_input + 1 if there's a hash of options at the end
263
286
unless supplied . is_a? Array
264
287
raise Vips ::Error , "unable to call #{ name } : " +
265
288
"argument array is not an array"
@@ -268,19 +291,21 @@ def self.call name, supplied, optional = {}, option_string = ""
268
291
raise Vips ::Error , "unable to call #{ name } : " +
269
292
"optional arguments are not a hash"
270
293
end
271
- if supplied . length != required_input . length
294
+
295
+ if supplied . length != introspect . required_input . length
272
296
raise Vips ::Error , "unable to call #{ name } : " +
273
297
"you supplied #{ supplied . length } arguments, " +
274
- "but operation needs #{ required_input . length } ."
298
+ "but operation needs " +
299
+ "#{ introspect . required_input . length } ."
275
300
end
276
301
277
- # very that all supplied_optional keys are in optional_input or
302
+ # all supplied_optional keys should be in optional_input or
278
303
# optional_output
279
304
optional . each do |key , _value |
280
305
arg_name = key . to_s
281
306
282
- unless optional_input . has_key? ( arg_name ) ||
283
- optional_output . has_key? ( arg_name )
307
+ unless introspect . optional_input . has_key? ( arg_name ) ||
308
+ introspect . optional_output . has_key? ( arg_name )
284
309
raise Vips ::Error , "unable to call #{ name } : " +
285
310
"unknown option #{ arg_name } "
286
311
end
@@ -303,12 +328,11 @@ def self.call name, supplied, optional = {}, option_string = ""
303
328
end
304
329
305
330
# set all required inputs
306
- required_input . each_index do |i |
307
- arg_name = required_input [ i ] [ 0 ]
308
- flags = required_input [ i ] [ 1 ]
331
+ introspect . required_input . each_index do |i |
332
+ arg_name , flags , gtype , blurb = introspect . required_input [ i ]
309
333
value = supplied [ i ]
310
334
311
- op . set arg_name , value , match_image , flags
335
+ op . set arg_name , value , match_image , flags , gtype
312
336
end
313
337
314
338
# set all optional inputs
@@ -317,18 +341,19 @@ def self.call name, supplied, optional = {}, option_string = ""
317
341
318
342
arg_name = key . to_s
319
343
320
- if optional_input . has_key? arg_name
321
- flags = optional_input [ arg_name ]
344
+ if introspect . optional_input . has_key? arg_name
345
+ _ , flags , gtype , blurb = introspect . optional_input [ arg_name ]
322
346
323
- op . set arg_name , value , match_image , flags
347
+ op . set arg_name , value , match_image , flags , gtype
324
348
end
325
349
end
326
350
327
351
op = op . build
328
352
329
353
# get all required results
330
354
result = [ ]
331
- required_output . each do |arg_name , _flags |
355
+ introspect . required_output . each do |details |
356
+ arg_name , flags , gtype , blurb = details
332
357
result << op . get ( arg_name )
333
358
end
334
359
@@ -337,7 +362,7 @@ def self.call name, supplied, optional = {}, option_string = ""
337
362
optional . each do |key , _value |
338
363
arg_name = key . to_s
339
364
340
- if optional_output . has_key? arg_name
365
+ if introspect . optional_output . has_key? arg_name
341
366
optional_results [ arg_name ] = op . get arg_name
342
367
end
343
368
end
0 commit comments