nwrfc 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -59,6 +59,11 @@ On Windows
59
59
 
60
60
  gem install nwrfc
61
61
 
62
+ == Documentation
63
+
64
+ Documentation is installed locally when you install the gem, but you can install it with `rdoc` or `yard` or whatever
65
+ if you have cloned the repository from GitHub.
66
+
62
67
  == Running the tests
63
68
  The test are located in the tests/ directory. The file `login_params.yaml` contains parameters that you will need
64
69
  to customize to log on to your local system that you are testing with. The YAML file contains parameters for multiple
data/lib/dev_rfc.trc CHANGED
@@ -131,3 +131,10 @@ ERROR pfuuid_init returns error -> UUIDs cannot be generated
131
131
  Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
132
132
 
133
133
  ERROR pfuuid_init returns error -> UUIDs cannot be generated
134
+
135
+ **** Trace file opened at 2012-02-17, 12:38:41 SAST
136
+ RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
137
+ Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
138
+ Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
139
+
140
+ ERROR pfuuid_init returns error -> UUIDs cannot be generated
data/lib/nwrfc.rb CHANGED
@@ -6,6 +6,7 @@
6
6
  # No ownership over any of these is asserted by Martin Ceronio
7
7
 
8
8
  require File.dirname(__FILE__)+'/nwrfc/nwrfclib'
9
+ require File.dirname(__FILE__)+'/nwrfc/datacontainer'
9
10
 
10
11
  require 'date'
11
12
  require 'time'
@@ -89,6 +90,45 @@ module NWRFC
89
90
 
90
91
  end
91
92
 
93
+ def NWRFC.abap_bool(value)
94
+ return true if value == 'X'
95
+ return false if value == ' '
96
+ nil
97
+ end
98
+
99
+ def NWRFC.bool_abap(value)
100
+ return 'X' if value == true
101
+ return ' ' if value == false
102
+ nil
103
+ end
104
+
105
+ # Represents a function parameter
106
+ class Parameter
107
+
108
+ attr_accessor :handle
109
+
110
+ # Create a parameter by setting parameter attributes
111
+ def initialize(*args)
112
+ attr = args[0]
113
+ @handle = NWRFCLib::RFCFuncParam.new
114
+ @handle[:name] = attr[:name].cU if attr[:name]
115
+ @handle[:direction] = NWRFCLib::RFC_DIRECTION[attr[:direction]] if attr[:direction]
116
+ @handle[:type] = NWRFCLib::RFC_TYPE[attr[:type]] if attr[:type]
117
+ @handle[:ucLength] = attr[:length] * 2 if attr[:length]
118
+ @handle[:nucLength] = attr[:length] if attr[:length]
119
+ @handle[:decimals] = attr[:decimals] if attr[:decimals]
120
+ # TODO: Add support for type description
121
+ #@handle[:typeDescHandle]
122
+ @handle[:defaultValue] = attr[:defaultValue].cU if attr[:defaultValue]
123
+ @handle[:parameterText] = attr[:parameterText].cU if attr[:parameterText]
124
+ @handle[:optional] = abap_bool(attr[:optional]) if attr[:optional]
125
+ end
126
+ end
127
+
128
+ class Type
129
+
130
+ end
131
+
92
132
  # Represents a remote-enabled function module for RFC, can be instantiated either by the caller
93
133
  # or by calling Connection#get_function. This only represents the description of the function;
94
134
  # to call a function, an instance of a function call must be obtained with #get_function_call
@@ -96,12 +136,28 @@ module NWRFC
96
136
  attr_reader :desc, :connection, :function_name
97
137
 
98
138
  # Get a function module instance; can also be obtained by calling Connection#get_function
99
- def initialize(connection, function_name)
100
- @function_name = function_name
139
+ # Takes either: (connection, function_name) or (function_name)
140
+ # When passed only `function_name`, creates a new function description locally, instead of
141
+ # fetching it form the server pointed to by connection
142
+ def initialize(*args)#(connection, function_name)
143
+ raise("Must initialize function with 1 or 2 arguments") if args.size != 1 && args.size != 2
101
144
  @error = NWRFCLib::RFCError.new
102
- @desc = NWRFCLib.get_function_desc(connection.handle, function_name.cU, @error.to_ptr)
103
- @connection = connection
104
- NWRFC.check_error(@error)
145
+ if args.size == 2
146
+ @function_name = args[1] #function_name
147
+ @desc = NWRFCLib.get_function_desc(args[0].handle, args[1].cU, @error.to_ptr)
148
+ NWRFC.check_error(@error)
149
+ @connection = args[0]
150
+ else
151
+ @function_name = args[0] #function_name
152
+ @desc = NWRFCLib::create_function_desc(args[0].cU, @error)
153
+ NWRFC.check_error(@error)
154
+ @connection = nil
155
+ end
156
+ end
157
+
158
+ def add_parameter(parameter)
159
+ rc = NWRFCLib.add_parameter(@desc, parameter.handle, @error)
160
+ NWRFC.check_error(@error) if rc > 0
105
161
  end
106
162
 
107
163
  # Create and return a callable instance of this function module
@@ -119,209 +175,6 @@ module NWRFC
119
175
 
120
176
  end
121
177
 
122
- # Representation of a data container (function, structure or table)
123
- class DataContainer
124
- attr_reader :handle, :desc
125
-
126
- def initialize(handle)
127
- @error = NWRFCLib::RFCError.new
128
- @handle = handle
129
- @desc = NWRFCLib.describe_type(@handle, @error)
130
- @member_metadata = {} #Cache of metadata for members
131
- NWRFC.check_error(@error)
132
- end
133
-
134
- # Return the member specified by string or symbol
135
- def [](element)
136
- member = element.to_s.upcase
137
- metadata = member_metadata(element)
138
- case metadata[:type]
139
- when :RFCTYPE_CHAR
140
- # TODO: Try use :string parameter in get_chars
141
- return read_chars(metadata)
142
- when :RFCTYPE_DATE
143
- return Date.parse(read_chars(metadata))
144
- #return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
145
- when :RFCTYPE_BCD
146
- size = metadata[:ucLength]
147
- cb = FFI::MemoryPointer.new :char, size * 2
148
- rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
149
- NWRFC.check_error(@error) if rc > 0
150
- cb.read_string(size).uC
151
- when :RFCTYPE_TIME
152
- # TODO: See whether we can optimize this
153
- timec = read_chars(metadata)
154
- return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
155
- when :RFCTYPE_BYTE
156
- return read_chars(metadata)
157
- when :RFCTYPE_TABLE
158
- new_handle = NWRFCLib::RFCDataContainer.new
159
- rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
160
- NWRFC.check_error(@error) if rc > 0
161
- # CAVEAT: Other calls using the handle require "handle" field
162
- # of the RFC_DATA_CONTAINER struct for some reason.
163
- new_handle = new_handle[:handle]
164
- value = Table.new(new_handle)
165
- when :RFCTYPE_NUM
166
- return read_chars(metadata).to_i
167
- when :RFCTYPE_FLOAT
168
- double = FFI::MemoryPointer.new :double
169
- rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
170
- NWRFC.check_error(@error) if rc > 0
171
- return double.get_double(0)
172
- when :RFCTYPE_INT
173
- int = FFI::MemoryPointer.new :int
174
- rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
175
- NWRFC.check_error(@error) if rc > 0
176
- return int.get_int(0)
177
- when :RFCTYPE_INT2
178
- short = FFI::MemoryPointer.new :short
179
- rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
180
- NWRFC.check_error(@error) if rc > 0
181
- return short.get_short(0)
182
- when :RFCTYPE_INT1
183
- int1 = FFI::MemoryPointer.new :uint8
184
- rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
185
- NWRFC.check_error(@error) if rc > 0
186
- return int1.get_uint8(0)
187
- when :RFCTYPE_NULL
188
- raise "Unsupported type RFCTYPE_NULL" #You should never run into this
189
- when :RFCTYPE_STRUCTURE
190
- new_handle = NWRFCLib::RFCDataContainer.new
191
- rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
192
- NWRFC.check_error(@error) if rc > 0
193
- new_handle = new_handle[:handle]
194
- value = Structure.new(new_handle)
195
- when :RFCTYPE_DECF16
196
- return read_chars(metadata).to_f
197
- when :RFCTYPE_DECF34
198
- return read_chars(metadata).to_f
199
- when :RFCTYPE_XMLDATA
200
- raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
201
- when :RFCTYPE_STRING
202
- return read_string(metadata)
203
- when :RFCTYPE_XSTRING
204
- else
205
- raise "Illegal member type #{metadata[:type]}"
206
- end
207
- NWRFC.check_error(@error)
208
- value
209
- end
210
-
211
- def []=(element, value)
212
- member = element.to_s.upcase
213
- metadata = member_metadata(element)
214
- case metadata[:type]
215
- when :RFCTYPE_CHAR
216
- NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
217
- when :RFCTYPE_DATE
218
- value = value_to_date(value)
219
- NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
220
- when :RFCTYPE_BCD
221
- when :RFCTYPE_TIME
222
- value = value_to_time(value)
223
- NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
224
- when :RFCTYPE_BYTE
225
- when :RFCTYPE_TABLE
226
- when :RFCTYPE_NUM
227
- when :RFCTYPE_FLOAT
228
- NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
229
- #NWRFCLib.set_chars(@handle, member.cU, value.to_s.cU, value.to_s.length, @error.to_ptr)
230
- when :RFCTYPE_INT
231
- NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
232
- when :RFCTYPE_INT2
233
- NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
234
- when :RFCTYPE_INT1
235
- NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
236
- when :RFCTYPE_NULL
237
- raise "Unsupported type RFCTYPE_NULL" #You should never run into this
238
- when :RFCTYPE_STRUCTURE
239
- when :RFCTYPE_DECF16
240
- when :RFCTYPE_DECF34
241
- when :RFCTYPE_XMLDATA
242
- when :RFCTYPE_STRING
243
- when :RFCTYPE_XSTRING
244
- else
245
- raise "Illegal member type #{@members[:type]}"
246
- end
247
- NWRFC.check_error(@error)
248
- end
249
-
250
- def value_to_time(value)
251
- return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
252
- value.to_s
253
- end
254
-
255
- def value_to_date(value)
256
- return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
257
- # Force the resulting string into 8 characters otherwise
258
- value = value.to_s
259
- value << ' ' until value.size == 8 if value.size < 8
260
- value = value[0..7] if value.size > 8
261
- value
262
- end
263
-
264
- def value_to_time(value)
265
- return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
266
- # Force the resulting string into 6 characters otherwise
267
- value = value.to_s
268
- value << ' ' until value.size == 6 if value.size < 6
269
- value = value[0..6] if value.size > 6
270
- value
271
- end
272
-
273
- # Get the metadata of a member (function, structure or table)
274
- def member_metadata(member_name)
275
- member = member_name.to_s.upcase
276
- if self.class == NWRFC::FunctionCall
277
- fpar = NWRFCLib::RFCFuncParam.new
278
- rc = NWRFCLib.get_parameter_desc_by_name(@desc, member.cU, fpar.to_ptr, @error.to_ptr)
279
- NWRFC.check_error(@error) if rc > 0
280
- member_to_hash(fpar)
281
- elsif self.class == NWRFC::Table || self.class == NWRFC::Structure
282
- fd = NWRFCLib::RFCFieldDesc.new
283
- rc = NWRFCLib.get_field_desc_by_name(@desc, member.cU, fd.to_ptr, @error.to_ptr)
284
- NWRFC.check_error(@error) if rc > 0
285
- member_to_hash(fd)
286
- end
287
- end
288
-
289
- private
290
- # Returns the subset of metadata values common to both a function parameter
291
- # and a type field
292
- def member_to_hash(member)
293
- {
294
- :name => member[:name].get_str,
295
- :type => NWRFCLib::RFCTYPE[member[:type]],
296
- :nucLength => member[:nucLength],
297
- :ucLength => member[:ucLength],
298
- :decimals => member[:decimals],
299
- :typeDescHandle => member[:typeDescHandle]
300
- }
301
- end
302
-
303
- def read_chars(metadata)
304
- size = metadata[:ucLength]
305
- cb = FFI::MemoryPointer.new :char, size
306
- rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, metadata[:nucLength], @error.to_ptr)
307
- NWRFC.check_error(@error) if rc > 0
308
- cb.read_string(size).uC
309
- end
310
-
311
- def read_string(metadata)
312
- #size = metadata[:ucLength]
313
- size = FFI::MemoryPointer.new(:uint)
314
- rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
315
- NWRFC.check_error(@error) if rc > 0
316
- buf_len = size.read_uint + 1
317
- sbuf = FFI::MemoryPointer.new :char, buf_len * NWRFCLib::B_SIZE
318
- rc = NWRFCLib.get_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
319
- NWRFC.check_error(@error) if rc > 0
320
- sbuf.read_string(sbuf.size).uC
321
- end
322
-
323
- end
324
-
325
178
  class FunctionCall < DataContainer
326
179
  attr_reader :handle, :desc, :connection, :function
327
180
 
@@ -0,0 +1,235 @@
1
+ module NWRFC
2
+
3
+ # Representation of a data container (function, structure or table)
4
+ class DataContainer
5
+ attr_reader :handle, :desc
6
+
7
+ def initialize(handle)
8
+ @error = NWRFCLib::RFCError.new
9
+ @handle = handle
10
+ @desc = NWRFCLib.describe_type(@handle, @error)
11
+ @member_metadata = {} #Cache of metadata for members
12
+ NWRFC.check_error(@error)
13
+ end
14
+
15
+ # Return the member specified by string or symbol
16
+ def [](element)
17
+ member = element.to_s.upcase
18
+ metadata = member_metadata(element)
19
+ case metadata[:type]
20
+ when :RFCTYPE_CHAR
21
+ # TODO: Try use :string parameter in get_chars
22
+ return read_chars(metadata)
23
+ when :RFCTYPE_DATE
24
+ return Date.parse(read_chars(metadata))
25
+ #return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
26
+ when :RFCTYPE_BCD
27
+ size = metadata[:ucLength]
28
+ cb = FFI::MemoryPointer.new :char, size * 2
29
+ rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
30
+ NWRFC.check_error(@error) if rc > 0
31
+ cb.read_string(size).uC
32
+ when :RFCTYPE_TIME
33
+ # TODO: See whether we can optimize this
34
+ timec = read_chars(metadata)
35
+ return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
36
+ when :RFCTYPE_BYTE
37
+ return read_chars(metadata)
38
+ when :RFCTYPE_TABLE
39
+ new_handle = NWRFCLib::RFCDataContainer.new
40
+ rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
41
+ NWRFC.check_error(@error) if rc > 0
42
+ # CAVEAT: Other calls using the handle require "handle" field
43
+ # of the RFC_DATA_CONTAINER struct for some reason.
44
+ new_handle = new_handle[:handle]
45
+ value = Table.new(new_handle)
46
+ when :RFCTYPE_NUM
47
+ return read_chars(metadata).to_i
48
+ when :RFCTYPE_FLOAT
49
+ double = FFI::MemoryPointer.new :double
50
+ rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
51
+ NWRFC.check_error(@error) if rc > 0
52
+ return double.get_double(0)
53
+ when :RFCTYPE_INT
54
+ int = FFI::MemoryPointer.new :int
55
+ rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
56
+ NWRFC.check_error(@error) if rc > 0
57
+ return int.get_int(0)
58
+ when :RFCTYPE_INT2
59
+ short = FFI::MemoryPointer.new :short
60
+ rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
61
+ NWRFC.check_error(@error) if rc > 0
62
+ return short.get_short(0)
63
+ when :RFCTYPE_INT1
64
+ int1 = FFI::MemoryPointer.new :uint8
65
+ rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
66
+ NWRFC.check_error(@error) if rc > 0
67
+ return int1.get_uint8(0)
68
+ when :RFCTYPE_NULL
69
+ raise "Unsupported type RFCTYPE_NULL" #You should never run into this
70
+ when :RFCTYPE_STRUCTURE
71
+ new_handle = NWRFCLib::RFCDataContainer.new
72
+ rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
73
+ NWRFC.check_error(@error) if rc > 0
74
+ new_handle = new_handle[:handle]
75
+ value = Structure.new(new_handle)
76
+ when :RFCTYPE_DECF16
77
+ double = FFI::MemoryPointer.new :double
78
+ rc = NWRFCLib.get_dec_f16(@handle, member.cU, double, @error)
79
+ NWRFC.check_error(@error) if rc > 0
80
+ return double.get_double(0)
81
+ when :RFCTYPE_DECF34
82
+ double = FFI::MemoryPointer.new :double, 2
83
+ rc = NWRFCLib.get_dec_f34(@handle, member.cU, double, @error)
84
+ NWRFC.check_error(@error) if rc > 0
85
+ return double.get_double(0)
86
+ when :RFCTYPE_XMLDATA
87
+ raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
88
+ when :RFCTYPE_STRING
89
+ return read_string(metadata)
90
+ when :RFCTYPE_XSTRING
91
+ size = FFI::MemoryPointer.new(:uint)
92
+ rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
93
+ NWRFC.check_error(@error) if rc > 0
94
+ buf_len = size.read_uint
95
+ sbuf = FFI::MemoryPointer.new :uchar, buf_len
96
+ rc = NWRFCLib.get_x_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
97
+ NWRFC.check_error(@error) if rc > 0
98
+ return sbuf.read_string(sbuf.size)
99
+ else
100
+ raise "Illegal member type #{metadata[:type]}"
101
+ end
102
+ NWRFC.check_error(@error)
103
+ value
104
+ end
105
+
106
+ def []=(element, value)
107
+ member = element.to_s.upcase
108
+ metadata = member_metadata(element)
109
+ case metadata[:type]
110
+ when :RFCTYPE_CHAR
111
+ NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
112
+ when :RFCTYPE_DATE
113
+ value = value_to_date(value)
114
+ NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
115
+ when :RFCTYPE_BCD
116
+ when :RFCTYPE_TIME
117
+ value = value_to_time(value)
118
+ NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
119
+ when :RFCTYPE_BYTE
120
+ when :RFCTYPE_TABLE
121
+ when :RFCTYPE_NUM
122
+ when :RFCTYPE_FLOAT
123
+ NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
124
+ #NWRFCLib.set_chars(@handle, member.cU, value.to_s.cU, value.to_s.length, @error.to_ptr)
125
+ when :RFCTYPE_INT
126
+ NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
127
+ when :RFCTYPE_INT2
128
+ NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
129
+ when :RFCTYPE_INT1
130
+ NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
131
+ when :RFCTYPE_NULL
132
+ raise "Unsupported type RFCTYPE_NULL" #You should never run into this
133
+ when :RFCTYPE_STRUCTURE
134
+ when :RFCTYPE_DECF16
135
+ raise "#{@members[:type]}: decfloat16 not supported yet"
136
+ double = NWRFCLib::RFC_DECF16.new #FFI::MemoryPointer.new :double
137
+ double[:align] = value.to_f
138
+ #double.put_double(0, value.to_f)
139
+ #double = FFI::Pointer.new 4
140
+ NWRFCLib.set_dec_f16(@handle, member.cU, double.pointer, @error)
141
+ when :RFCTYPE_DECF34
142
+ raise "#{@members[:type]}: decfloat34 not supported yet"
143
+ # double = FFI::MemoryPointer.new :double, 2
144
+ # double.put_double(0, value.to_f)
145
+ double = NWRFCLib::RFC_DECF34.new #FFI::MemoryPointer.new :double
146
+ double[:align] = value.to_f
147
+ NWRFCLib.set_dec_f34(@handle, member.cU, double, @error)
148
+ when :RFCTYPE_XMLDATA
149
+ raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
150
+ when :RFCTYPE_STRING
151
+ when :RFCTYPE_XSTRING
152
+ m = FFI::MemoryPointer.new value.size
153
+ m.put_bytes 0, value
154
+ NWRFCLib.set_x_string(@handle, member.cU, m, value.size, @error)
155
+ else
156
+ raise "Illegal member type #{@members[:type]}"
157
+ end
158
+ NWRFC.check_error(@error)
159
+ end
160
+
161
+ def value_to_time(value)
162
+ return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
163
+ value.to_s
164
+ end
165
+
166
+ def value_to_date(value)
167
+ return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
168
+ # Force the resulting string into 8 characters otherwise
169
+ value = value.to_s
170
+ value << ' ' until value.size == 8 if value.size < 8
171
+ value = value[0..7] if value.size > 8
172
+ value
173
+ end
174
+
175
+ def value_to_time(value)
176
+ return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
177
+ # Force the resulting string into 6 characters otherwise
178
+ value = value.to_s
179
+ value << ' ' until value.size == 6 if value.size < 6
180
+ value = value[0..6] if value.size > 6
181
+ value
182
+ end
183
+
184
+ # Get the metadata of a member (function, structure or table)
185
+ def member_metadata(member_name)
186
+ member = member_name.to_s.upcase
187
+ if self.class == NWRFC::FunctionCall
188
+ fpar = NWRFCLib::RFCFuncParam.new
189
+ rc = NWRFCLib.get_parameter_desc_by_name(@desc, member.cU, fpar.to_ptr, @error.to_ptr)
190
+ NWRFC.check_error(@error) if rc > 0
191
+ member_to_hash(fpar)
192
+ elsif self.class == NWRFC::Table || self.class == NWRFC::Structure
193
+ fd = NWRFCLib::RFCFieldDesc.new
194
+ rc = NWRFCLib.get_field_desc_by_name(@desc, member.cU, fd.to_ptr, @error.to_ptr)
195
+ NWRFC.check_error(@error) if rc > 0
196
+ member_to_hash(fd)
197
+ end
198
+ end
199
+
200
+ private
201
+ # Returns the subset of metadata values common to both a function parameter
202
+ # and a type field
203
+ def member_to_hash(member)
204
+ {
205
+ :name => member[:name].get_str,
206
+ :type => NWRFCLib::RFC_TYPE[member[:type]],
207
+ :nucLength => member[:nucLength],
208
+ :ucLength => member[:ucLength],
209
+ :decimals => member[:decimals],
210
+ :typeDescHandle => member[:typeDescHandle]
211
+ }
212
+ end
213
+
214
+ def read_chars(metadata)
215
+ size = metadata[:ucLength]
216
+ cb = FFI::MemoryPointer.new :char, size
217
+ rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, metadata[:nucLength], @error.to_ptr)
218
+ NWRFC.check_error(@error) if rc > 0
219
+ cb.read_string(size).uC
220
+ end
221
+
222
+ def read_string(metadata)
223
+ size = FFI::MemoryPointer.new(:uint)
224
+ rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
225
+ NWRFC.check_error(@error) if rc > 0
226
+ buf_len = size.read_uint + 1
227
+ sbuf = FFI::MemoryPointer.new :char, buf_len * NWRFCLib::B_SIZE
228
+ rc = NWRFCLib.get_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
229
+ NWRFC.check_error(@error) if rc > 0
230
+ sbuf.read_string(sbuf.size).uC
231
+ end
232
+
233
+ end
234
+
235
+ end
@@ -0,0 +1,28 @@
1
+
2
+ **** Trace file opened at 2012-02-17, 14:29:25 SAST
3
+ RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
4
+ Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
5
+ Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
6
+
7
+ ERROR pfuuid_init returns error -> UUIDs cannot be generated
8
+
9
+ **** Trace file opened at 2012-02-17, 14:35:20 SAST
10
+ RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
11
+ Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
12
+ Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
13
+
14
+ ERROR pfuuid_init returns error -> UUIDs cannot be generated
15
+
16
+ **** Trace file opened at 2012-02-17, 14:50:20 SAST
17
+ RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
18
+ Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
19
+ Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
20
+
21
+ ERROR pfuuid_init returns error -> UUIDs cannot be generated
22
+
23
+ **** Trace file opened at 2012-02-17, 15:04:13 SAST
24
+ RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
25
+ Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
26
+ Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
27
+
28
+ ERROR pfuuid_init returns error -> UUIDs cannot be generated
@@ -15,6 +15,7 @@ RUBY_VERSION_18 = RUBY_VERSION[0..2] == "1.8"
15
15
  # See http://stackoverflow.com/questions/9035661/ruby-ffi-memorypointer-read-int-present-in-1-9-but-not-1-8
16
16
  # Probably not good to interpret an unsigned int as an int, but we don't expect to use it for big values
17
17
  # that could result in sign conversion
18
+ # FIXME - This must go! Replace with calls to get_* defined in FFI::MemoryPointer
18
19
  if RUBY_VERSION_18
19
20
  FFI::MemoryPointer.class_eval{ alias :read_uint :read_int}
20
21
  end
@@ -59,27 +60,24 @@ class String
59
60
  end
60
61
 
61
62
  end
62
- #String.class_eval{define_method(:cU){ NWRFCLib::Cutf8_to_utf16le.iconv(self+"\0") }}
63
63
 
64
64
  # Enhancement to FFI::StructLayout::CharArray to add a get_str method that changes the
65
65
  # string value of the character array by enforcing encoding of UTF-16LE (as used in NW RFC SDK)
66
66
  # and strips off blanks at the end to return a readable String
67
67
  class FFI::StructLayout::CharArray
68
68
  def get_str
69
- #Iconv.conv("UTF8", "UTF-16LE", self.to_ptr.read_string(self.size)).strip
70
69
  NWRFCLib::Cutf16le_to_utf8.iconv(self.to_ptr.read_string(self.size)).strip
71
70
  end
72
71
  end
73
72
 
74
73
  # Library wrapper around NW RFC SDK shared library using RUBY-FFI
75
- # FIXME: Make structs managed structs and deconstruct them on GC
76
74
  module NWRFCLib
77
75
 
78
- Cutf8_to_utf16le = Iconv.new("UTF-16LE", "UTF8")
79
- Cutf16le_to_utf8 = Iconv.new("UTF8", "UTF-16LE")
76
+ Cutf8_to_utf16le = Iconv.new("UTF-16LE", "UTF-8")
77
+ Cutf16le_to_utf8 = Iconv.new("UTF-8", "UTF-16LE")
80
78
 
81
79
  extend FFI::Library
82
- ffi_lib '/home/martin/nwrfcsdk/lib/libsapnwrfc.so'
80
+ ffi_lib 'sapnwrfc'
83
81
 
84
82
  # Multiplier for providing correct byte size for String passed to RFC library
85
83
  #TODO: Make platform-dependent size based on RUBY_PLATFORM
@@ -132,7 +130,7 @@ module NWRFCLib
132
130
  :RFC_TABLES, 7
133
131
  )
134
132
 
135
- RFCTYPE = enum(
133
+ RFC_TYPE = enum(
136
134
  :RFCTYPE_CHAR , 0,
137
135
  :RFCTYPE_DATE , 1,
138
136
  :RFCTYPE_BCD , 2,
@@ -245,59 +243,29 @@ module NWRFCLib
245
243
  layout :handle, :pointer
246
244
  end
247
245
 
248
- #---
249
- # attach_function :init, :RfcInit, [], :void
250
- # # Connection handling:
251
- # attach_function :open_connection, :RfcOpenConnection,
252
- # [:pointer, :uint, :pointer], :pointer
253
- # attach_function :close_connection, :RfcCloseConnection,
254
- # [:pointer, :pointer], :void #(handle, error)
255
- # attach_function :get_connection_attributes, :RfcGetConnectionAttributes,
256
- # [:pointer, :pointer, :pointer], :void #(conn_handle, conninfo, error)
257
- # # Function Handling & Calling
258
- # attach_function :get_function_desc, :RfcGetFunctionDesc,
259
- # [:pointer, :pointer, :pointer], :pointer #(conn_handle, func_name, error)
260
- # attach_function :create_function, :RfcCreateFunction,
261
- # [:pointer, :pointer], :pointer #(fd_handle, error), :func_handle
262
- # attach_function :invoke, :RfcInvoke,
263
- # [:pointer, :pointer, :pointer], :int #(conn_handle, func_handle, error), RC
264
- # #TODO: Do we want to include RfcDestroyFunction for releasing its memory?
265
- # attach_function :get_param_count, :RfcGetParameterCount,
266
- # [:pointer, :pointer, :pointer], :void #(fd_handle, uint, error)
267
- # attach_function :get_parameter_desc_by_index, :RfcGetParameterDescByIndex,
268
- # [:pointer, :uint, :pointer, :pointer], :void #(fd_handle, idx, param, error)
269
- # # Field Handling
270
- # # RFC_RC RfcGetChars(handle, name, buffer, length, error)
271
- # attach_function :get_chars, :RfcGetChars,
272
- # [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
273
- # # RFC_RC RfcGetChars(handle, name, buffer, length, error)
274
- # attach_function :get_num, :RfcGetNum,
275
- # [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
276
- # # RFC_RC RfcGetDate
277
- # attach_function :get_date, :RfcGetDate,
278
- # [:pointer, :pointer, [:char, 8], :pointer], :RFC_RC
279
- # # RFC_RC RfcGetDate
280
- # attach_function :get_time, :RfcGetTime,
281
- # [:pointer, :pointer, [:char, 6], :pointer], :RFC_RC
282
- # # RFC_RC RfcGetString
283
- # # attach_function :get_string, :RfcGetString,
284
- # # [:pointer, :pointer, :pointer], :RFC_RC
285
- # # RFC RfcGetBytes
286
- # attach_function :get_bytes, :RfcGetBytes,
287
- # [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
288
- # # RFC_RC RfcGetXString
289
- # attach_function :get_xstring, :RfcGetXString,
290
- # [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :RFC_RC
291
- # # RFC_RC RfcGetStringLength(dataHandle, name, *length, error)
292
- # attach_function :get_string_length, :RfcGetStringLength,
293
- # [:pointer, :pointer, :pointer, :pointer], :int
294
- # # void RfcSetChars(dataHandle, name, value, length, error)
295
- # attach_function :set_chars, :RfcSetChars,
296
- # [:pointer, :pointer, :pointer, :uint, :pointer], :void
297
- #+++
246
+ class RFC_DECF16 < FFI::Union
247
+ layout :bytes, [:uchar, 8],
248
+ :align, :double
249
+ end
250
+
251
+ # class SAP_MAX_ALIGN_T < FFI::Union
252
+ # layout :align1, :long,
253
+ # :align2, :double,
254
+ # :align3, :pointer,
255
+ # :align4,
256
+ # end
257
+
258
+ # class RFC_DECF34 < FFI::Union
259
+ # layout :bytes, [:uchar, 16],
260
+ # :align, 16
261
+ # end
298
262
 
299
263
  #############################################################################################################
300
264
  # ATTACH FUNCTIONS
265
+ # The functions here were obtained by parsing content from the doxygen files from the documentation
266
+ # accompanying the NW RFC SDK, and were tweaked here and there afterward. Most of them are actually not
267
+ # yet used in our NWRFC library, so calling them may not work. For best results, consult sapnwrfc.h from
268
+ # the SDK
301
269
  #############################################################################################################
302
270
  [
303
271
  [:add_exception, :RfcAddException, [:pointer, :pointer, :pointer], :int],
@@ -399,7 +367,8 @@ module NWRFCLib
399
367
  [:set_bytes, :RfcSetBytes, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
400
368
  [:set_chars, :RfcSetChars, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
401
369
  [:set_date, :RfcSetDate, [:pointer, :pointer, :pointer, :pointer], :int],
402
- [:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
370
+ #[:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
371
+ [:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, RFC_DECF16.by_value, :pointer], :int],
403
372
  [:set_dec_f34, :RfcSetDecF34, [:pointer, :pointer, :pointer, :pointer], :int],
404
373
  [:set_float, :RfcSetFloat, [:pointer, :pointer, :double, :pointer], :int],
405
374
  [:set_ini_path, :RfcSetIniPath, [:pointer, :pointer], :int],
@@ -423,12 +392,13 @@ module NWRFCLib
423
392
  [:submit_transaction, :RfcSubmitTransaction, [:pointer, :pointer], :int],
424
393
  [:utf8_to_sapuc, :RfcUTF8ToSAPUC, [:pointer, :uint, :pointer, :pointer, :pointer, :pointer], :int]
425
394
  ].each{|funcsig|
426
- # puts funcsig.to_s
427
395
  attach_function(funcsig[0], funcsig[1], funcsig[2], funcsig[3])
428
396
  }
429
397
 
430
398
  # Take Hash of connection parameters and returns FFI pointer to an array
431
399
  # for passing to connection
400
+ # ---
401
+ # TODO - Ideally, this method should live in nwrfc.rb
432
402
  def NWRFCLib.make_conn_params(params) #https://github.com/ffi/ffi/wiki/Structs
433
403
  par = FFI::MemoryPointer.new(RFCConnParam, params.length)
434
404
  pars = params.length.times.collect do |i|
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwrfc
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 0
10
- version: 0.0.0
9
+ - 1
10
+ version: 0.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Martin Ceronio
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-30 00:00:00 Z
18
+ date: 2012-02-20 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: SAP Netweaver RFC Library Wrapper using Ruby-FFI
@@ -29,9 +29,10 @@ extra_rdoc_files:
29
29
  files:
30
30
  - README.rdoc
31
31
  - Rakefile
32
- - lib/nwrfc.old.rb
33
32
  - lib/nwrfc.rb
33
+ - lib/nwrfc/datacontainer.rb
34
34
  - lib/nwrfc/nwrfclib.rb
35
+ - lib/nwrfc/dev_rfc.trc
35
36
  - lib/dev_rfc.trc
36
37
  homepage: http://rubygems.org/gems/nwrfc
37
38
  licenses: []
data/lib/nwrfc.old.rb DELETED
@@ -1,338 +0,0 @@
1
- require File.dirname(__FILE__)+'/nwrfc/nwrfclib'
2
-
3
- # This library provides a way to call the functions of the SAP Netweaver RFC
4
- # SDK, i.e. opening a connection to an ABAP system, calling functions etc., as
5
- # well as running an RFC service
6
- #---
7
- # *TODO*: Create an error class that wraps the SAP error struct, so it can
8
- # be raised and the caller can get all the information from there
9
- #+++
10
-
11
- module NWRFC
12
-
13
- def inspect
14
- self.to_s
15
- end
16
-
17
- def NWRFC.check_error(error_handle)
18
- raise "Error code #{error_handle[:code]} group #{error_handle[:group]} message #{error_handle[:message].get_str}" \
19
- if error_handle[:code] > 0
20
- end
21
-
22
- # Representation of a data container (function, structure or table)
23
- module DataContainer
24
-
25
- def initialize(handle)
26
- @handle = handle
27
- @error = NWRFCLib::RFCError.new
28
- end
29
-
30
- # Return the member specified by string or symbol
31
- def [](element)
32
- element = element.upcase
33
- metadata = member_metadata(element)
34
- case metadata[:type]
35
- when :RFCTYPE_CHAR
36
- # TODO: Try use :string parameter in get_chars
37
- size = metadata[:ucLength]
38
- cb = FFI::MemoryPointer.new :char, size
39
- NWRFCLib.get_chars(@handle, element.cU, cb, metadata[:nucLength], @error.to_ptr)
40
- value = cb.read_string(size).uC
41
- when :RFCTYPE_DATE
42
- when :RFCTYPE_BCD
43
- when :RFCTYPE_TIME
44
- when :RFCTYPE_BYTE
45
- when :RFCTYPE_TABLE
46
- value = get_data_container(element, :table)
47
- when :RFCTYPE_NUM
48
- when :RFCTYPE_FLOAT
49
- when :RFCTYPE_INT
50
- when :RFCTYPE_INT2
51
- when :RFCTYPE_INT1
52
- when :RFCTYPE_NULL
53
- when :RFCTYPE_STRUCTURE
54
- value = get_data_container(element, :structure)
55
- when :RFCTYPE_DECF16
56
- when :RFCTYPE_DECF34
57
- when :RFCTYPE_XMLDATA
58
- when :RFCTYPE_STRING
59
- when :RFCTYPE_XSTRING
60
- else
61
- raise "Illegal member type #{metadata[:type]}"
62
- end
63
- NWRFC.check_error(@error)
64
- value
65
- end
66
-
67
- def []=(element, value)
68
- metadata = member_metadata(element)
69
- case member_metadata[element][:type]
70
- when :RFCTYPE_CHAR
71
- NWRFCLib.set_chars(@handle, element.cU, value.cU, value.length, @error.to_ptr)
72
- when :RFCTYPE_DATE
73
- when :RFCTYPE_BCD
74
- when :RFCTYPE_TIME
75
- when :RFCTYPE_BYTE
76
- when :RFCTYPE_TABLE
77
- when :RFCTYPE_NUM
78
- when :RFCTYPE_FLOAT
79
- when :RFCTYPE_INT
80
- when :RFCTYPE_INT2
81
- when :RFCTYPE_INT1
82
- when :RFCTYPE_NULL
83
- when :RFCTYPE_STRUCTURE
84
- when :RFCTYPE_DECF16
85
- when :RFCTYPE_DECF34
86
- when :RFCTYPE_XMLDATA
87
- when :RFCTYPE_STRING
88
- when :RFCTYPE_XSTRING
89
- else
90
- raise "Illegal member type #{@members[:type]}"
91
- end
92
- NWRFC.check_error(@error)
93
- end
94
-
95
- # Get the metadata of a member (function, structure or table)
96
- def member_metadata(member)
97
- if self.class == NWRFC::FunctionCall
98
- self.function_description.member_metadata(member)
99
- elsif self.class.instance_of?(Table) || self.class.instance_of?(Structure)
100
- NWRFCLib.get_field_desc_by_name(@handle, member.uC, )
101
- end
102
- end
103
-
104
- private
105
-
106
- # Returns the subset of metadata values common to both a function parameter
107
- # and a type field
108
- def member_to_hash(member)
109
- {
110
- :type => NWRFCLib::RFCTYPE[member[:type]],
111
- :nucLength => member[:nucLength],
112
- :ucLength => member[:ucLength],
113
- :decimals => member[:decimals],
114
- :typeDescHandle => member[:typeDescHandle]
115
- }
116
- end
117
-
118
- # Return either table or structure representing the element given
119
- # from the current data container
120
- def get_data_container(element, type)
121
- datac = FFI::MemoryPointer.new NWRFCLib::RFCDataContainer
122
- if type == :table
123
- NWRFCLib.get_table(@handle, element.cU, datac, @error.to_ptr)
124
- @components[element] = Table.new(datac)
125
- end
126
- if type == :structure
127
- NWRFCLib.get_structure(@handle, element.cU, datac, @error.to_ptr)
128
- @components[element] = Structure.new(datac)
129
- end
130
- NWRFC.check_error(@error)
131
- end
132
-
133
- end
134
-
135
- # Represents a connection to a SAP system that can be used to invoke
136
- # remote-enabled functions
137
- class Connection
138
-
139
- attr_reader :handle, :error
140
-
141
- # Opens a connection to the SAP system with the given connection parameters
142
- # (described in the NW RFC SDK document), passed in the form of a Hash, e.g.
143
- # Connection.new { 'ashost' :=> 'ajax.domain.com', ... }
144
- def initialize(conn_params)
145
- conn_params.untaint #For params loaded from file, e.g.
146
- raise "Connection parameters must be a Hash" unless conn_params.instance_of? Hash
147
- #NWRFCLib.init
148
- @cparams = NWRFCLib.make_conn_params(conn_params)
149
- raise "Could not create valid pointer from parameters" unless @cparams.instance_of? FFI::MemoryPointer
150
- #@errp = FFI::MemoryPointer.new(NWRFCLib::RFCError)
151
- @error = NWRFCLib::RFCError.new #@errp
152
- @handle = NWRFCLib.open_connection(@cparams, conn_params.length, @error.to_ptr)
153
- NWRFC.check_error(@error)
154
- self
155
- end
156
-
157
- # Call the NW RFC SDK's RfcCloseConnection() function with the current
158
- # connection; this (should - *TODO* - check) invalidate the connection handle
159
- # and cause an error on any subsequent use of this connection
160
- def disconnect
161
- NWRFCLib.close_connection(@handle, @error.to_ptr)
162
- NWRFC.check_error(@error)
163
- end
164
-
165
- # Return details about the current connection and the system
166
- def connection_info
167
- return @get_connection_attributes if @get_connection_attributes
168
- conn_info = NWRFCLib::RFCConnection.new
169
- NWRFCLib.get_connection_attributes(@handle, conn_info.to_ptr, @error.to_ptr)
170
- check_error
171
- @get_connection_attributes = conn_info.members.inject({}) {|hash, member|
172
- hash[member] = conn_info[member].get_str #get_str, own definition in nwrfclib.rb, FFI::StructLayout::CharArray#get_str
173
- hash
174
- }
175
- end
176
-
177
- def get_function(func_name)
178
- Function.new(self, func_name)
179
- end
180
-
181
- # Check the status of the error structure; raise an exception if it
182
- # contains an error
183
- # *TODO* - Raise a more meaningful error
184
- def check_error
185
- raise "Error code #{@error[:code]} group #{@error[:group]}" if @error[:code] > 0
186
- end
187
-
188
- end
189
-
190
- # Represents a remote-enabled function module for RFC, can be instantiated either by the caller
191
- # or by calling Connection#get_function. This only represents the description of the function;
192
- # to call a function, an instance of a function call must be obtained with #get_function_call
193
- #---
194
- # FIXME: We are using a shared error object in the connection, so what happens in a
195
- # multi-threaded situation? Functions should each have their own error handle
196
- #+++
197
- class Function
198
- attr_reader :func_desc, :connection, :function_name, :members
199
-
200
- # Get a function module instance; can also be obtained by calling Connection#get_function
201
- def initialize(connection, func_name)
202
- @connection = connection
203
- @func_desc = NWRFCLib.get_function_desc(@connection.handle, func_name.cU, @connection.error.to_ptr)
204
- NWRFC.check_error(@connection.error)
205
- @function_name = func_name
206
- @error = NWRFCLib::RFCError.new
207
- @members = self_describe # Load the metadata of the function description
208
- end
209
-
210
- # Create and return a callable instance of this function module
211
- def get_function_call
212
- FunctionCall.new(self)
213
- end
214
-
215
- def parameter_count
216
- pcount = FFI::MemoryPointer.new(:uint)
217
- NWRFCLib.get_parameter_count(@func_desc, pcount, @error.to_ptr)
218
- NWRFC.check_error(@error)
219
- pcount.read_uint
220
- end
221
-
222
- # Returns the definitions of parameters associated with this function module (lazy loading)
223
- def parameters
224
- @members
225
- end
226
-
227
- def [](param)
228
- member_metadata(param)
229
- end
230
-
231
- # Look up parameter by method name given, returns parameter instance
232
- # if it refers to a valid parameter
233
- def method_missing(method_sym, *args, &block)
234
- param_name = method_sym.to_s.upcase
235
- fpar = NWRFCLib::RFCFuncParam.new
236
- rc = NWRFCLib.get_parameter_desc_by_name(@func_desc, param_name.cU, fpar.to_ptr, @error.to_ptr)
237
- NWRFC.check_error(@error) if rc > 0
238
- parameter_to_hash(fpar)
239
- end
240
-
241
- def member_metadata(param)
242
- param_name = param.to_s.upcase
243
- fpar = NWRFCLib::RFCFuncParam.new
244
- rc = NWRFCLib.get_parameter_desc_by_name(@func_desc, param_name.cU, fpar.to_ptr, @error.to_ptr)
245
- NWRFC.check_error(@error) if rc > 0
246
- parameter_to_hash(fpar)
247
- end
248
-
249
- private
250
-
251
- def parameter_to_hash(param)
252
- {
253
- :type => NWRFCLib::RFCTYPE[param[:type]],
254
- :direction => NWRFCLib::RFC_DIRECTION[param[:direction]],
255
- :nucLength => param[:nucLength],
256
- :ucLength => param[:ucLength],
257
- :decimals => param[:decimals],
258
- :typeDescHandle => param[:typeDescHandle],
259
- :defaultValue => param[:defaultValue].get_str,
260
- :parameterText => param[:parameterText].get_str,
261
- :optional => param[:optional]
262
- }
263
- end
264
-
265
- # Load the metadata of the function description (only called during init)
266
- def self_describe
267
- parameter_count.times.inject({}) do |params, index|
268
- param = NWRFCLib::RFCFuncParam.new
269
- NWRFCLib.get_parameter_desc_by_index(@func_desc, index, param.to_ptr, @error.to_ptr)
270
- params[param[:name].get_str] = {
271
- :type => NWRFCLib::RFCTYPE[param[:type]],
272
- :direction => NWRFCLib::RFC_DIRECTION[param[:direction]],
273
- :nucLength => param[:nucLength],
274
- :ucLength => param[:ucLength],
275
- :decimals => param[:decimals],
276
- :typeDescHandle => param[:typeDescHandle],
277
- :defaultValue => param[:defaultValue].get_str,
278
- :parameterText => param[:parameterText].get_str,
279
- :optional => param[:optional]
280
- }
281
- params
282
- end
283
- end
284
-
285
- end
286
-
287
- # Represents a callable instance of a function module, using a function module description
288
- # obtained previously. Can be obtained by passing either a function description or
289
- # calling Function#get_function_call
290
- class FunctionCall
291
- include DataContainer
292
- attr_reader :function_description, :handle, :connection
293
-
294
- def initialize(function_description)
295
- @error = NWRFCLib::RFCError.new
296
- @function_description = function_description
297
- @connection = function_description.connection
298
- @handle = NWRFCLib.create_function(@function_description.func_desc, @error.to_ptr)
299
- @members = function_description
300
- NWRFC.check_error(@error)
301
- end
302
-
303
- # Execute the function call on the SAP server
304
- def invoke
305
- rc = NWRFCLib.invoke(@connection.handle, @handle, @connection.error.to_ptr)
306
- NWRFC.check_error(@error) if rc > 0
307
- end
308
-
309
- def method_missing(method_sym, *args, &block)
310
- param_name = method_sym.to_s.upcase
311
- # fpar = NWRFCLib::RFCFuncParam.new
312
- # rc = NWRFCLib.get_parameter_desc_by_name(@function_description, param_name.cU, fpar.to_ptr, @error.to_ptr)
313
- # NWRFC.check_error(@error) if rc > 0
314
- if param_name[-1..-1] == "="
315
- self[:param_name] = *args[0]
316
- else
317
- self[:param_name]
318
- end
319
- end
320
-
321
- end
322
-
323
- # Represents a structure
324
- class Structure
325
- include DataContainer
326
- end
327
-
328
- # Represents a table
329
- class Table
330
- include DataContainer
331
- end
332
-
333
- # Wrapper around the RFC Server functionality
334
- class Server
335
-
336
- end
337
-
338
- end