nwrfc-aphid 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.rdoc +189 -0
- data/Rakefile +8 -0
- data/lib/nwrfc/datacontainer.rb +346 -0
- data/lib/nwrfc/nwerror.rb +40 -0
- data/lib/nwrfc/nwrfclib.rb +474 -0
- data/lib/nwrfc/server.rb +48 -0
- data/lib/nwrfc.rb +495 -0
- metadata +109 -0
data/lib/nwrfc.rb
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# Author:: Martin Ceronio martin.ceronio@infosize.co.za
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Martin Ceronio
|
|
3
|
+
# License:: MIT and/or Creative Commons Attribution-ShareAlike
|
|
4
|
+
# SAP, Netweaver, RFC and other names referred to in this code
|
|
5
|
+
# are, or may be registered trademarks and the property of SAP, AG
|
|
6
|
+
# No ownership over any of these is asserted by Martin Ceronio
|
|
7
|
+
|
|
8
|
+
require File.dirname(__FILE__)+'/nwrfc/nwrfclib'
|
|
9
|
+
require File.dirname(__FILE__)+'/nwrfc/datacontainer'
|
|
10
|
+
require File.dirname(__FILE__)+'/nwrfc/server'
|
|
11
|
+
require File.dirname(__FILE__)+'/nwrfc/nwerror'
|
|
12
|
+
|
|
13
|
+
require 'date'
|
|
14
|
+
require 'time'
|
|
15
|
+
|
|
16
|
+
# This library provides a way to call the functions of the SAP Netweaver RFC
|
|
17
|
+
# SDK, i.e. opening a connection to an ABAP system, calling functions etc., as
|
|
18
|
+
# well as running an RFC service
|
|
19
|
+
|
|
20
|
+
module NWRFC
|
|
21
|
+
|
|
22
|
+
# ABAP Time Format ("HHMMSS")
|
|
23
|
+
NW_TIME_FORMAT = "%H%M%S"
|
|
24
|
+
# ABAP Date Format ("YYYYMMDD")
|
|
25
|
+
NW_DATE_FORMAT = "%Y%m%d"
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
self.to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Return the version of the NW RFC SDK library
|
|
32
|
+
def NWRFC.get_version
|
|
33
|
+
# See custom method FFI::Pointer#read_string_dn in nwrfclib.rb
|
|
34
|
+
# http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
|
|
35
|
+
major = FFI::MemoryPointer.new(:uint)
|
|
36
|
+
minor = FFI::MemoryPointer.new(:uint)
|
|
37
|
+
patch = FFI::MemoryPointer.new(:uint)
|
|
38
|
+
version = NWRFCLib.get_version(major, minor, patch)
|
|
39
|
+
[version.read_string_dn.uC, major.read_uint, minor.read_uint, patch.read_uint]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Take Hash of connection parameters and returns FFI pointer to an array
|
|
43
|
+
# for setting up a connection
|
|
44
|
+
def NWRFC.make_conn_params(params) #https://github.com/ffi/ffi/wiki/Structs
|
|
45
|
+
par = FFI::MemoryPointer.new(NWRFCLib::RFCConnParam, params.length)
|
|
46
|
+
pars = params.length.times.collect do |i|
|
|
47
|
+
NWRFCLib::RFCConnParam.new(par + i * NWRFCLib::RFCConnParam.size)
|
|
48
|
+
end
|
|
49
|
+
tpar = params.to_a
|
|
50
|
+
params.length.times do |n|
|
|
51
|
+
pars[n][:name] = FFI::MemoryPointer.from_string(tpar[n][0].to_s.cU)
|
|
52
|
+
pars[n][:value] = FFI::MemoryPointer.from_string(tpar[n][1].to_s.cU)
|
|
53
|
+
end
|
|
54
|
+
par
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Check for an error using error handle (used internally)
|
|
58
|
+
def NWRFC.check_error(error_handle)
|
|
59
|
+
raise NWError, error_handle \
|
|
60
|
+
if error_handle[:code] > 0
|
|
61
|
+
#raise "Error code #{error_handle[:code]} group #{error_handle[:group]} message #{error_handle[:message].get_str}" \
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Represents a client connection to a SAP system that can be used to invoke
|
|
66
|
+
# remote-enabled functions
|
|
67
|
+
class Connection
|
|
68
|
+
attr_reader :handle
|
|
69
|
+
|
|
70
|
+
# Opens a connection to the SAP system with the given connection parameters
|
|
71
|
+
# (described in the NW RFC SDK document), passed in the form of a Hash, e.g.
|
|
72
|
+
# Connection.new { 'ashost' :=> 'ajax.domain.com', ... }
|
|
73
|
+
def initialize(conn_params)
|
|
74
|
+
Rails.logger.info "NWRFC#open_connection" if defined?(Rails)
|
|
75
|
+
raise "Connection parameters must be a Hash" unless conn_params.instance_of? Hash
|
|
76
|
+
@cparams = NWRFC.make_conn_params(conn_params)
|
|
77
|
+
raise "Could not create valid pointer from parameters" unless @cparams.instance_of? FFI::MemoryPointer
|
|
78
|
+
@error = NWRFCLib::RFCError.new
|
|
79
|
+
@handle = NWRFCLib.open_connection(@cparams, conn_params.length, @error.to_ptr)
|
|
80
|
+
NWRFC.check_error(@error)
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Close the current connection and clear its handle after successful cleanup.
|
|
85
|
+
def disconnect
|
|
86
|
+
return unless @handle
|
|
87
|
+
rc = NWRFCLib.close_connection(@handle, @error.to_ptr)
|
|
88
|
+
NWRFC.check_error(@error) if rc > 0
|
|
89
|
+
@handle = nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Get the description of a given function module from the system to which we are connected
|
|
93
|
+
# @return [Function] function module description
|
|
94
|
+
def get_function(function_name)
|
|
95
|
+
Rails.logger.info "NWRFC#get_function(#{function_name})" if defined?(Rails)
|
|
96
|
+
Function.new(self, function_name)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Return details about the current connection and the system
|
|
100
|
+
# @return [Hash] information about the current connection
|
|
101
|
+
def connection_info
|
|
102
|
+
return @get_connection_attributes if @get_connection_attributes
|
|
103
|
+
conn_info = NWRFCLib::RFCConnection.new
|
|
104
|
+
rc = NWRFCLib.get_connection_attributes(@handle, conn_info.to_ptr, @error)
|
|
105
|
+
NWRFC.check_error(@error) if rc > 0
|
|
106
|
+
@get_connection_attributes = conn_info.members.inject({}) {|hash, member|
|
|
107
|
+
hash[member] = conn_info[member].get_str #get_str, own definition in nwrfclib.rb, FFI::StructLayout::CharArray#get_str
|
|
108
|
+
hash
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
alias :close :disconnect
|
|
113
|
+
|
|
114
|
+
def start_transaction(queue_name = nil)
|
|
115
|
+
@tid = FFI::MemoryPointer.new(:char, 50)
|
|
116
|
+
rc = NWRFCLib.get_transaction_id(@handle, @tid, @error)
|
|
117
|
+
NWRFC.check_error(@error) if rc > 0
|
|
118
|
+
queue_name = FFI::MemoryPointer.from_string(queue_name.to_s.cU) if queue_name
|
|
119
|
+
transaction_handle = NWRFCLib.create_transaction(@handle, @tid, queue_name, @error)
|
|
120
|
+
NWRFC.check_error(@error)
|
|
121
|
+
Transaction.new(transaction_handle)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class Transaction
|
|
127
|
+
attr_reader :handle
|
|
128
|
+
|
|
129
|
+
def initialize(handle)
|
|
130
|
+
@handle = handle
|
|
131
|
+
@error = NWRFCLib::RFCError.new
|
|
132
|
+
@submitted = false
|
|
133
|
+
@confirmed = false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def commit
|
|
137
|
+
unless @submitted
|
|
138
|
+
rc = NWRFCLib.submit_transaction(@handle, @error)
|
|
139
|
+
NWRFC.check_error(@error) if rc > 0
|
|
140
|
+
@submitted = true
|
|
141
|
+
end
|
|
142
|
+
unless @confirmed
|
|
143
|
+
rc = NWRFCLib.confirm_transaction(@handle, @error)
|
|
144
|
+
NWRFC.check_error(@error) if rc > 0
|
|
145
|
+
@confirmed = true
|
|
146
|
+
end
|
|
147
|
+
close
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def close
|
|
151
|
+
return unless @handle
|
|
152
|
+
rc = NWRFCLib.destroy_transaction(@handle, @error)
|
|
153
|
+
NWRFC.check_error(@error) if rc > 0
|
|
154
|
+
@handle = nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
alias :submit :commit
|
|
158
|
+
alias :destroy :close
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Converts ABAP true/false into Ruby true/false
|
|
163
|
+
# @return True for 'X', False for ' ' or nil otherwise
|
|
164
|
+
def NWRFC.abap_bool(value)
|
|
165
|
+
return true if value == 'X'
|
|
166
|
+
return false if value == ' '
|
|
167
|
+
nil
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Converts Ruby true/false into ABAP true/false
|
|
171
|
+
# @return 'X' for true,, ' ' for false or nil otherwise
|
|
172
|
+
def NWRFC.bool_abap(value)
|
|
173
|
+
return 'X' if value == true
|
|
174
|
+
return ' ' if value == false
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Represents the metadata of a function parameter
|
|
179
|
+
class Parameter
|
|
180
|
+
|
|
181
|
+
attr_accessor :handle
|
|
182
|
+
|
|
183
|
+
# Create a parameter by setting parameter attributes
|
|
184
|
+
#@todo For certain types, e.g. :RFCTYPE_BCD, a length specification is
|
|
185
|
+
# required, otherwise a segfault is the result later down the line.
|
|
186
|
+
# Find and implement all the types where this is required
|
|
187
|
+
def initialize(*args)
|
|
188
|
+
|
|
189
|
+
attr = args[0]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
raise "RFCTYPE_BCD requires a length" if attr[:type] == :RFCTYPE_BCD && !(attr[:length])
|
|
194
|
+
|
|
195
|
+
@handle = NWRFCLib::RFCFuncParam.new
|
|
196
|
+
@handle[:name] = attr[:name].cU if attr[:name]
|
|
197
|
+
@handle[:direction] = NWRFCLib::RFC_DIRECTION[attr[:direction]] if attr[:direction]
|
|
198
|
+
@handle[:type] = NWRFCLib::RFC_TYPE[attr[:type]] if attr[:type]
|
|
199
|
+
@handle[:ucLength] = attr[:length] * 2 if attr[:length]
|
|
200
|
+
@handle[:nucLength] = attr[:length] if attr[:length]
|
|
201
|
+
@handle[:decimals] = attr[:decimals] if attr[:decimals]
|
|
202
|
+
# TODO: Add support for type description
|
|
203
|
+
#@handle[:typeDescHandle]
|
|
204
|
+
@handle[:defaultValue] = attr[:defaultValue].cU if attr[:defaultValue]
|
|
205
|
+
@handle[:parameterText] = attr[:parameterText].cU if attr[:parameterText]
|
|
206
|
+
@handle[:optional] = abap_bool(attr[:optional]) if attr[:optional]
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class Type
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Represents a remote-enabled function module for RFC, can be instantiated either by the caller
|
|
215
|
+
# or by calling Connection#get_function. This only represents the description of the function;
|
|
216
|
+
# to call a function, an instance of a function call must be obtained with #get_function_call
|
|
217
|
+
class Function
|
|
218
|
+
attr_reader :desc, :function_name
|
|
219
|
+
attr_accessor :connection
|
|
220
|
+
|
|
221
|
+
# Get a function module instance; can also be obtained by calling Connection#get_function
|
|
222
|
+
# Takes either: (connection, function_name) or (function_name)
|
|
223
|
+
# When passed only `function_name`, creates a new function description locally, instead of
|
|
224
|
+
# fetching it form the server pointed to by connection
|
|
225
|
+
#@overload new(connection, function_name)
|
|
226
|
+
# Fetches a function definition from the server pointed to by the connection
|
|
227
|
+
# @param [Connection] connection Connection to SAP ABAP system
|
|
228
|
+
# @param [String] function_name Name of the function module on the connected system
|
|
229
|
+
#
|
|
230
|
+
#@overload new(function_name)
|
|
231
|
+
# Returns a new function descriptor. This is ideally used in the case of establishing a
|
|
232
|
+
# server function. In this case, the function cannot be used to make a remote function call.
|
|
233
|
+
# @param [String] function_name Name of the new function module
|
|
234
|
+
def initialize(*args)#(connection, function_name)
|
|
235
|
+
raise("Must initialize function with 1 or 2 arguments") if args.size != 1 && args.size != 2
|
|
236
|
+
@error = NWRFCLib::RFCError.new
|
|
237
|
+
@active_function_calls = 0
|
|
238
|
+
if args.size == 2
|
|
239
|
+
@function_name = args[1] #function_name
|
|
240
|
+
@desc = NWRFCLib.get_function_desc(args[0].handle, args[1].cU, @error.to_ptr)
|
|
241
|
+
NWRFC.check_error(@error)
|
|
242
|
+
@connection = args[0]
|
|
243
|
+
@owns_desc = false
|
|
244
|
+
else
|
|
245
|
+
@function_name = args[0] #function_name
|
|
246
|
+
@desc = NWRFCLib::create_function_desc(args[0].cU, @error)
|
|
247
|
+
NWRFC.check_error(@error)
|
|
248
|
+
@connection = nil
|
|
249
|
+
@owns_desc = true
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Add a parameter to a function module. Ideally to be used in the case where a function definition is built
|
|
254
|
+
# up in the client code, rather than fetching it from the server for a remote call
|
|
255
|
+
# @param [Parameter] Definition of a function module parameter
|
|
256
|
+
def add_parameter(parameter)
|
|
257
|
+
rc = NWRFCLib.add_parameter(@desc, parameter.handle, @error)
|
|
258
|
+
NWRFC.check_error(@error) if rc > 0
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Create and return a callable instance of this function module
|
|
262
|
+
def get_function_call
|
|
263
|
+
FunctionCall.new(self)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Yield a function call and release its container, including nested data,
|
|
267
|
+
# even when the block raises.
|
|
268
|
+
def with_function_call
|
|
269
|
+
function_call = get_function_call
|
|
270
|
+
begin
|
|
271
|
+
yield function_call
|
|
272
|
+
ensure
|
|
273
|
+
function_call.close
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def close
|
|
278
|
+
return unless @desc
|
|
279
|
+
if @owns_desc
|
|
280
|
+
raise "Cannot close function description while function calls are active" if @active_function_calls > 0
|
|
281
|
+
rc = NWRFCLib.destroy_function_desc(@desc, @error)
|
|
282
|
+
NWRFC.check_error(@error) if rc > 0
|
|
283
|
+
end
|
|
284
|
+
@desc = nil
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
alias :destroy :close
|
|
288
|
+
|
|
289
|
+
# Get the number of parameters this function has
|
|
290
|
+
def parameter_count
|
|
291
|
+
pcount = FFI::MemoryPointer.new(:uint)
|
|
292
|
+
rc = NWRFCLib.get_parameter_count(@desc, pcount, @error)
|
|
293
|
+
NWRFC.check_error(@error) if rc > 0
|
|
294
|
+
pcount.read_uint
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Return the description of parameters associated with this Function
|
|
298
|
+
def parameters
|
|
299
|
+
parameter_count.times.inject({}) do |params, index|
|
|
300
|
+
param = NWRFCLib::RFCFuncParam.new
|
|
301
|
+
NWRFCLib.get_parameter_desc_by_index(@desc, index, param.to_ptr, @error.to_ptr)
|
|
302
|
+
params[param[:name].get_str] = {
|
|
303
|
+
:type => NWRFCLib::RFC_TYPE[param[:type]],
|
|
304
|
+
:direction => NWRFCLib::RFC_DIRECTION[param[:direction]],
|
|
305
|
+
:nucLength => param[:nucLength],
|
|
306
|
+
:ucLength => param[:ucLength],
|
|
307
|
+
:decimals => param[:decimals],
|
|
308
|
+
:typeDescHandle => param[:typeDescHandle],
|
|
309
|
+
:defaultValue => param[:defaultValue].get_str,
|
|
310
|
+
:parameterText => param[:parameterText].get_str,
|
|
311
|
+
:optional => param[:optional]
|
|
312
|
+
}
|
|
313
|
+
params
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
protected
|
|
318
|
+
|
|
319
|
+
def function_call_opened
|
|
320
|
+
@active_function_calls += 1
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def function_call_closed
|
|
324
|
+
@active_function_calls -= 1
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Represents a callable instance of a function
|
|
330
|
+
class FunctionCall < DataContainer
|
|
331
|
+
attr_reader :handle, :desc, :connection, :function
|
|
332
|
+
|
|
333
|
+
# Call with either Function or Connection and Function Call instance (handle)
|
|
334
|
+
#@overload new(function)
|
|
335
|
+
# Get a function call instance from the function description
|
|
336
|
+
# @param [Function] function Function Description
|
|
337
|
+
#@overload new(function_handle)
|
|
338
|
+
# Used in the case of server functions; instantiate a function call instance from the connection
|
|
339
|
+
# and function description handles received when function is invoked on our side from a remote
|
|
340
|
+
# system; in this case, there is no handle to the connection, and we take advantage only of the
|
|
341
|
+
# data container capabilities
|
|
342
|
+
# @param [FFI::Pointer] function_handle Pointer to the function handle (RFC_FUNCTION_HANDLE)
|
|
343
|
+
def initialize(*args)
|
|
344
|
+
@error = NWRFCLib::RFCError.new
|
|
345
|
+
if args[0].kind_of?(FFI::Pointer)
|
|
346
|
+
@handle = args[0]
|
|
347
|
+
@owns_handle = false
|
|
348
|
+
@connection = nil
|
|
349
|
+
@function = nil
|
|
350
|
+
# @connection = args[0].connection
|
|
351
|
+
@desc = NWRFCLib.describe_function(@handle, @error)
|
|
352
|
+
#@todo Investigate having a referenced Function object as well in the server case; does it have practical applications?
|
|
353
|
+
# Doing this would require an extra way of handling the constructor of Function
|
|
354
|
+
# @function = Function.new
|
|
355
|
+
elsif args[0].kind_of?(Function)
|
|
356
|
+
@function = args[0] #function
|
|
357
|
+
@owns_handle = true
|
|
358
|
+
@connection = args[0].connection
|
|
359
|
+
@handle = NWRFCLib.create_function(@function.desc, @error.to_ptr)
|
|
360
|
+
@desc = args[0].desc
|
|
361
|
+
end
|
|
362
|
+
NWRFC.check_error(@error)
|
|
363
|
+
@function.send(:function_call_opened) if @function
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def close
|
|
367
|
+
return unless @handle
|
|
368
|
+
if @owns_handle
|
|
369
|
+
rc = NWRFCLib.destroy_function(@handle, @error.to_ptr)
|
|
370
|
+
NWRFC.check_error(@error) if rc > 0
|
|
371
|
+
end
|
|
372
|
+
@handle = nil
|
|
373
|
+
@desc = nil
|
|
374
|
+
@function.send(:function_call_closed) if @function
|
|
375
|
+
@function = nil
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
alias :destroy :close
|
|
379
|
+
|
|
380
|
+
# Execute the function on the connected ABAP system
|
|
381
|
+
#@raise NWRFC::NWError
|
|
382
|
+
def invoke(tx = nil)
|
|
383
|
+
Rails.logger.info "NWRFC#invoke" if defined?(Rails)
|
|
384
|
+
raise "Not a callable function" unless @connection
|
|
385
|
+
if tx
|
|
386
|
+
rc = NWRFCLib.invoke_in_transaction(tx.handle, @handle, @error.to_ptr)
|
|
387
|
+
NWRFC.check_error(@error) if rc > 0
|
|
388
|
+
else
|
|
389
|
+
rc = NWRFCLib.invoke(@connection.handle, @handle, @error.to_ptr)
|
|
390
|
+
#@todo Handle function exceptions by checking for :RFC_ABAP_EXCEPTION (5)
|
|
391
|
+
NWRFC.check_error(@error) if rc > 0
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Returns whether or not a given parameter is active, i.e. whether it will be sent to the server during the RFC
|
|
396
|
+
# call with FunctionCall#invoke. This is helpful for functions that set default values on parameters or otherwise
|
|
397
|
+
# check whether parameters are passed in cases where this may have an impact on performance or otherwise
|
|
398
|
+
# @param[String, Symbol] parameter Name of the parameter
|
|
399
|
+
def active?(parameter)
|
|
400
|
+
is_active = FFI::MemoryPointer.new :int
|
|
401
|
+
rc = NWRFCLib.is_parameter_active(@handle, parameter.to_s.cU, is_active, @error)
|
|
402
|
+
NWRFC.check_error(@error) if rc > 0
|
|
403
|
+
is_active.read_int == 1
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Set a named parameter to active or inactive
|
|
407
|
+
def set_active(parameter, active=true)
|
|
408
|
+
(active ? active_flag = 1 : active_flag = 0)
|
|
409
|
+
rc = NWRFCLib.set_parameter_active(@handle, parameter.to_s.cU, active_flag, @error)
|
|
410
|
+
NWRFC.check_error(@error) if rc > 0
|
|
411
|
+
active
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# Set a named parameter to inactive
|
|
415
|
+
def deactivate(parameter)
|
|
416
|
+
set_active(parameter, false)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class Table < DataContainer
|
|
423
|
+
|
|
424
|
+
include Enumerable
|
|
425
|
+
|
|
426
|
+
# Iterate over the rows in a table. Each row is yielded as a structure
|
|
427
|
+
def each(&block) #:yields row
|
|
428
|
+
return [] if size == 0
|
|
429
|
+
rc = NWRFCLib.move_to_first_row(@handle, @error)
|
|
430
|
+
NWRFC.check_error(@error) if rc > 0
|
|
431
|
+
size.times do |row|
|
|
432
|
+
struct_handle = NWRFCLib.get_current_row(@handle, @error)
|
|
433
|
+
NWRFC.check_error(@error)
|
|
434
|
+
NWRFCLib.move_to_next_row(@handle, @error)
|
|
435
|
+
# CAVEAT: Other calls using the handle require "handle" field
|
|
436
|
+
# of the RFC_DATA_CONTAINER struct
|
|
437
|
+
yield Structure.new(struct_handle)
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Return the number of rows in the table
|
|
442
|
+
def size
|
|
443
|
+
rows = FFI::MemoryPointer.new(:uint)
|
|
444
|
+
rc = NWRFCLib.get_row_count(@handle, rows, @error)
|
|
445
|
+
rows.read_uint
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Delete all rows from (empty) the table
|
|
449
|
+
def clear
|
|
450
|
+
rc = NWRFCLib.delete_all_rows(@handle, @error)
|
|
451
|
+
NWRFC.check_error(@error) if rc > 0
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Retrieve the row at the given index
|
|
455
|
+
def [](index)
|
|
456
|
+
rc = NWRFCLib.move_to(@handle, index, @error)
|
|
457
|
+
NWRFC.check_error(@error) if rc > 0
|
|
458
|
+
struct_handle = NWRFCLib.get_current_row(@handle, @error)
|
|
459
|
+
NWRFC.check_error(@error)
|
|
460
|
+
Structure.new(struct_handle)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Append a row (structure) to the table
|
|
464
|
+
def append(row)
|
|
465
|
+
raise "Must append a structure" unless row.class == NWRFC::Structure
|
|
466
|
+
rc = NWRFCLib.append_row(@handle, row.handle, @error)
|
|
467
|
+
NWRFC.check_error(@error) if rc > 0
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Add new (empty) row and return the structure handle
|
|
471
|
+
# or yield it to a passed block
|
|
472
|
+
# @return Structure
|
|
473
|
+
def new_row
|
|
474
|
+
s_handle = NWRFCLib.append_new_row(@handle, @error)
|
|
475
|
+
NWRFC.check_error(@error)
|
|
476
|
+
s = Structure.new(s_handle)
|
|
477
|
+
if block_given?
|
|
478
|
+
yield s
|
|
479
|
+
else
|
|
480
|
+
s
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
end #class Table
|
|
485
|
+
|
|
486
|
+
# Represents a structure. An instance is obtained internally by passing the
|
|
487
|
+
# handle of a structure. A user can obtain an instance by invoking sub-field
|
|
488
|
+
# access of a structure or a function
|
|
489
|
+
class Structure < DataContainer
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
end # class Structure
|
|
494
|
+
|
|
495
|
+
end #module NWRFC
|
metadata
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: nwrfc-aphid
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Martin Ceronio
|
|
8
|
+
- Charles Dale
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bigdecimal
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: ffi
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 1.17.3
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 1.17.3
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: test-unit
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
description: A maintained fork of nwrfc, an SAP NetWeaver RFC Library wrapper using
|
|
70
|
+
Ruby-FFI
|
|
71
|
+
email:
|
|
72
|
+
- mydoghasworms@gmail.com
|
|
73
|
+
- rubygems@aphid.net
|
|
74
|
+
executables: []
|
|
75
|
+
extensions: []
|
|
76
|
+
extra_rdoc_files:
|
|
77
|
+
- README.rdoc
|
|
78
|
+
files:
|
|
79
|
+
- README.rdoc
|
|
80
|
+
- Rakefile
|
|
81
|
+
- lib/nwrfc.rb
|
|
82
|
+
- lib/nwrfc/datacontainer.rb
|
|
83
|
+
- lib/nwrfc/nwerror.rb
|
|
84
|
+
- lib/nwrfc/nwrfclib.rb
|
|
85
|
+
- lib/nwrfc/server.rb
|
|
86
|
+
homepage: https://github.com/chuckd/nwrfc
|
|
87
|
+
licenses:
|
|
88
|
+
- MIT
|
|
89
|
+
metadata:
|
|
90
|
+
source_code_uri: https://github.com/chuckd/nwrfc
|
|
91
|
+
rubygems_mfa_required: 'true'
|
|
92
|
+
rdoc_options: []
|
|
93
|
+
require_paths:
|
|
94
|
+
- lib
|
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '2.5'
|
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
requirements: []
|
|
106
|
+
rubygems_version: 4.0.16
|
|
107
|
+
specification_version: 4
|
|
108
|
+
summary: Maintained SAP NetWeaver RFC Library wrapper
|
|
109
|
+
test_files: []
|