nwrfc 0.0.0 → 0.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.
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