dde 0.2.8 → 0.2.9
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/VERSION +1 -1
- data/bin/dde_main +8 -5
- data/dde.gemspec +2 -2
- data/lib/dde/client.rb +51 -1
- data/lib/dde/dde_string.rb +1 -1
- data/lib/dde/monitor.rb +2 -1
- data/lib/dde/xl_server.rb +38 -61
- data/lib/dde/xl_table.rb +37 -17
- data/spec/dde/app_shared.rb +1 -1
- data/spec/dde/app_spec.rb +0 -1
- data/spec/dde/client_spec.rb +28 -32
- data/spec/dde/monitor_spec.rb +7 -67
- data/spec/dde/server_shared.rb +55 -67
- data/spec/dde/server_spec.rb +12 -5
- data/spec/dde/xl_server_spec.rb +12 -11
- data/spec/dde/xl_table_spec.rb +43 -4
- data/spec/spec_helper.rb +110 -49
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.9
|
data/bin/dde_main
CHANGED
@@ -20,11 +20,14 @@ end
|
|
20
20
|
cout "Starting DDE server with service 'excel'\n"
|
21
21
|
server = DDE::XlServer.new.start_service
|
22
22
|
|
23
|
-
|
23
|
+
# Command line args define actions to be run after each successful DDE data transaction
|
24
|
+
server.actions = ARGV.empty? ? [:timer] : ARGV
|
25
|
+
|
26
|
+
# Starting message loop (necessary for DDE message processing)
|
27
|
+
cout "Starting DDE message loop\n"
|
24
28
|
|
25
|
-
|
26
|
-
cout "Starting message loop\n"
|
29
|
+
msg = Msg.new # pointer to Msg FFI struct
|
27
30
|
while msg = get_message(msg)
|
28
|
-
|
29
|
-
|
31
|
+
translate_message(msg);
|
32
|
+
dispatch_message(msg);
|
30
33
|
end
|
data/dde.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dde}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["arvicco"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-23}
|
13
13
|
s.default_executable = %q{dde_main}
|
14
14
|
s.description = %q{Server that mimics Excel receiving XLTable data via DDE protocol}
|
15
15
|
s.email = %q{arvitallian@gmail.com}
|
data/lib/dde/client.rb
CHANGED
@@ -13,7 +13,7 @@ module DDE
|
|
13
13
|
# super init_flags, &dde_callback
|
14
14
|
# end
|
15
15
|
|
16
|
-
#
|
16
|
+
# Establish a conversation with a server application that supports the specified service
|
17
17
|
# name and topic name pair.
|
18
18
|
def start_conversation( service=nil, topic=nil )
|
19
19
|
try "Starting conversation #{service} #{topic}", DDE::Errors::ClientError do
|
@@ -29,6 +29,7 @@ module DDE
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
# Stops active conversation, raises error if no conversations active
|
32
33
|
def stop_conversation
|
33
34
|
try "Stopping conversation", DDE::Errors::ClientError do
|
34
35
|
error "DDE not started" unless dde_active?
|
@@ -45,6 +46,55 @@ module DDE
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
# Sends XTYP_POKE transaction to server if conversation was already established.
|
50
|
+
# data:: data being sent (will be coerced to String unless is already a (packed) String)
|
51
|
+
# format:: standard clipboard format of submitted data item (default CF_TEXT)
|
52
|
+
def send_data( data, format = CF_TEXT, item = "" )
|
53
|
+
data_pointer = FFI::MemoryPointer.from_string(data.to_s)
|
54
|
+
result, trans_id = start_transaction(XTYP_POKE, data_pointer, data_pointer.size, format, item)
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
# Initiates transaction to server if conversation was already established.
|
59
|
+
# transaction_type:: XTYP_ADVSTART, XTYP_ADVSTOP, XTYP_EXECUTE, XTYP_POKE, XTYP_REQUEST
|
60
|
+
# data_pointer:: pointer to data being sent (either FFI::MemoryPointer or DDE data_handle)
|
61
|
+
# cb:: data set size (or -1 to indicate that data_pointer is in fact DDE data_handle)
|
62
|
+
# format:: standard clipboard format of submitted data item (default CF_TEXT)
|
63
|
+
# item:: item to which transaction is related (String, DdeString or DDE string handle)
|
64
|
+
# timeout:: timeout in milliseconds or TIMEOUT_ASYNC to indicate async transaction
|
65
|
+
#
|
66
|
+
# *Returns*:: A pair of [result, trans_id]. Result is nil for failed transactions,
|
67
|
+
# DDE data handle for synchronous transactions in which the client expects data from the server,
|
68
|
+
# nonzero for successful transactions where clients does not expect data from server.
|
69
|
+
# Trans_id: for asynchronous transactions, a unique transaction identifier for use with the
|
70
|
+
# DdeAbandonTransaction function and the XTYP_XACT_COMPLETE transaction. For synchronous transactions,
|
71
|
+
# the low-order word of this variable contains any applicable DDE_ flags resulting from the transaction.
|
72
|
+
#
|
73
|
+
def start_transaction( transaction_type, data_pointer=nil, cb = data_pointer ? data_pointer.size : 0,
|
74
|
+
format=CF_TEXT, item=0, timeout=1000)
|
75
|
+
|
76
|
+
result = nil
|
77
|
+
trans_id = FFI::MemoryPointer.new(:uint32).put_uint32(0,0)
|
78
|
+
|
79
|
+
try "Sending data to server", DDE::Errors::ClientError do
|
80
|
+
error "DDE not started" unless dde_active?
|
81
|
+
error "Conversation not started" unless conversation_active?
|
82
|
+
|
83
|
+
item_handle = case item
|
84
|
+
when String
|
85
|
+
DDE::DdeString.new(@id, service).handle
|
86
|
+
when DdeString
|
87
|
+
item.handle
|
88
|
+
else
|
89
|
+
item
|
90
|
+
end
|
91
|
+
|
92
|
+
error unless result = dde_client_transaction(data_pointer, cb, @conversation, item_handle,
|
93
|
+
format, transaction_type, timeout, trans_id)
|
94
|
+
end
|
95
|
+
[result, trans_id.get_uint32(0)]
|
96
|
+
end
|
97
|
+
|
48
98
|
def conversation_active?
|
49
99
|
!!@conversation
|
50
100
|
end
|
data/lib/dde/dde_string.rb
CHANGED
@@ -26,7 +26,7 @@ module DDE
|
|
26
26
|
end
|
27
27
|
rescue => e
|
28
28
|
end
|
29
|
-
raise DDE::Errors::StringError, "Failed to initialize DDE string: #{e}" unless @handle && @name && !e
|
29
|
+
raise DDE::Errors::StringError, "Failed to initialize DDE string: #{e} #{e.backtrace.join("\n")}" unless @handle && @name && !e
|
30
30
|
super @name
|
31
31
|
end
|
32
32
|
end
|
data/lib/dde/monitor.rb
CHANGED
@@ -6,7 +6,7 @@ module DDE
|
|
6
6
|
attr_accessor :print, :calls
|
7
7
|
|
8
8
|
# Creates new DDE monitor instance
|
9
|
-
def initialize(init_flags=nil, &callback)
|
9
|
+
def initialize(init_flags=nil, print = nil, &callback)
|
10
10
|
init_flags ||=
|
11
11
|
APPCLASS_MONITOR | # this is monitor
|
12
12
|
MF_CALLBACKS | # monitor callback functions
|
@@ -17,6 +17,7 @@ module DDE
|
|
17
17
|
MF_POSTMSGS | # monitor posted DDE messages
|
18
18
|
MF_SENDMSGS # monitor sent DDE messages
|
19
19
|
|
20
|
+
@print = print
|
20
21
|
@calls = []
|
21
22
|
|
22
23
|
callback ||= lambda do |*args|
|
data/lib/dde/xl_server.rb
CHANGED
@@ -7,12 +7,14 @@ module DDE
|
|
7
7
|
class XlServer < Server
|
8
8
|
|
9
9
|
attr_reader :format, # data format(s) (registered clipboard formats) that server supports
|
10
|
-
:
|
10
|
+
:data # data storage/processor
|
11
|
+
|
12
|
+
attr_accessor :actions # Actions to be run on table after each successful DDE input (:draw, :debug, :timer)
|
11
13
|
|
12
14
|
# Creates new Xl Server instance
|
13
15
|
def initialize(init_flags = nil, &dde_callback )
|
14
16
|
|
15
|
-
@
|
17
|
+
@data = DDE::XlTable.new
|
16
18
|
|
17
19
|
# Trying to register or retrieve existing format XlTable
|
18
20
|
try 'Registering format XlTable', DDE::Errors::FormatError do
|
@@ -25,88 +27,63 @@ module DDE
|
|
25
27
|
# HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
|
26
28
|
# HDDEDATA hData, DWORD dwData1, DWORD dwData2)
|
27
29
|
def default_callback
|
28
|
-
lambda do |type, format, conv, hsz1, hsz2,
|
30
|
+
lambda do |type, format, conv, hsz1, hsz2, data_handle, data1, data2|
|
29
31
|
case type
|
30
32
|
when XTYP_CONNECT # Request to connect from client, creating data exchange channel
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
# callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS flag
|
48
|
-
# in the DdeInitialize function).
|
33
|
+
# format:: Not used.
|
34
|
+
# conv:: Not used.
|
35
|
+
# hsz1:: Handle to the topic name.
|
36
|
+
# hsz2:: Handle to the service name.
|
37
|
+
# data_handle:: Handle to DDE data. Meaning depends on the type of the current transaction.
|
38
|
+
# data1:: Pointer to a CONVCONTEXT structure that contains context information for the conversation.
|
39
|
+
# If the client is not a DDEML application, this parameter is 0.
|
40
|
+
# data2:: Specifies whether the client is the same application instance as the server. If the parameter
|
41
|
+
# is 1, the client is the same instance. If it is 0, the client is a different instance.
|
42
|
+
# *Returns*:: A server callback function should return TRUE(1, but DDE_FACK works just fine too)
|
43
|
+
# to allow the client to establish a conversation on the specified service name and topic
|
44
|
+
# name pair, or the function should return FALSE to deny the conversation. If the callback
|
45
|
+
# function returns TRUE and a conversation is successfully established, the system passes
|
46
|
+
# the conversation handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to
|
47
|
+
# the server's callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS
|
48
|
+
# flag in the DdeInitialize function).
|
49
49
|
|
50
50
|
if hsz2 == @service.handle
|
51
51
|
cout "Service #{@service}: connect requested by client\n"
|
52
|
-
|
52
|
+
DDE_FACK # instead of true # Yes, this server supports requested (name) handle
|
53
53
|
else
|
54
54
|
cout "Service #{@service} unable to process connection request for #{hsz2}\n"
|
55
55
|
DDE_FNOTPROCESSED # 0 instead of false # No, server does not support requested (name) handle
|
56
56
|
end
|
57
57
|
|
58
58
|
when XTYP_POKE # Client initiated XTYP_POKE transaction to push unsolicited data to the server
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
#
|
70
|
-
|
71
|
-
#
|
72
|
-
@
|
73
|
-
# // Placing table into print queue
|
74
|
-
# WaitForSingleObject(hMutex1,INFINITE);
|
75
|
-
# q.push(server.xltable);
|
76
|
-
# ReleaseMutex(hMutex1);
|
77
|
-
# // Allowing the table output thread to start...
|
78
|
-
# ReleaseSemaphore(hSemaphore,1,NULL);
|
79
|
-
#
|
59
|
+
# format:: Specifies the format of the data sent from the server.
|
60
|
+
# conv:: Handle to the conversation.
|
61
|
+
# hsz1:: Handle to the topic name. (Excel: [topic]item ?!)
|
62
|
+
# hsz2:: Handle to the item name.
|
63
|
+
# data_handle:: Handle to the data that the client is sending to the server.
|
64
|
+
# *Returns*:: A server callback function should return the DDE_FACK flag if it processes this
|
65
|
+
# transaction, the DDE_FBUSY flag if it is too busy to process this transaction,
|
66
|
+
# or the DDE_FNOTPROCESSED flag if it rejects this transaction.
|
67
|
+
|
68
|
+
@data.topic = dde_query_string(@id, hsz1) # Convert hsz1 into "[topic]item" string and
|
69
|
+
if @data.receive(data_handle) # Receive incoming DDE data and process it
|
70
|
+
|
71
|
+
# Perform actions like :draw, :debug, :timer, :formats on received data (default :timer)
|
72
|
+
@actions.each{|action| @data.send(action.to_sym)}
|
80
73
|
DDE_FACK # Transaction successful
|
81
74
|
else
|
75
|
+
@data.debug
|
82
76
|
cout "Service #{@service} unable to process data request (XTYP_POKE) for #{hsz2}"
|
83
77
|
DDE_FNOTPROCESSED # 0 Transaction NOT successful - return (HDDEDATA)TRUE; ?!(why TRUE, not FALSE)
|
84
78
|
end
|
85
|
-
|
86
|
-
when XTYP_DISCONNECT # DDE client disconnects
|
87
|
-
# server.xltable.Delete();
|
88
|
-
# break;
|
89
|
-
DDE_FNOTPROCESSED # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
|
90
|
-
|
91
|
-
when XTYP_ERROR # DDE Error
|
92
|
-
# WaitForSingleObject(hMutex, INFINITE);
|
93
|
-
# std::cerr<<"DDE error.\n";
|
94
|
-
# ReleaseMutex(hMutex);
|
95
|
-
# break;
|
96
|
-
DDE_FNOTPROCESSED # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
|
97
|
-
|
98
79
|
else
|
99
80
|
DDE_FNOTPROCESSED # 0 - return((HDDEDATA)NULL);// is it the same as 0 ?!
|
100
81
|
end
|
101
82
|
end
|
102
83
|
end
|
103
84
|
|
104
|
-
# Make 'excel' the default name for named service
|
105
|
-
alias_method :__start_service, :start_service
|
106
|
-
|
107
85
|
def start_service( name='excel', init_flags=nil, &dde_callback)
|
108
|
-
dde_callback
|
109
|
-
__start_service( name, init_flags, &dde_callback )
|
86
|
+
super name, init_flags, &dde_callback || default_callback
|
110
87
|
end
|
111
88
|
|
112
89
|
end
|
data/lib/dde/xl_table.rb
CHANGED
@@ -66,13 +66,25 @@ module DDE
|
|
66
66
|
@table.each{|row| cout @topic; row.each {|col| cout " #{col}"}; cout "\n"}
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def debug
|
70
|
+
return false if empty?
|
71
|
+
Encoding.default_external = 'cp866'
|
72
|
+
# omitting separator gymnastics for now
|
73
|
+
cout "-----\n"
|
74
|
+
@table.each_with_index{|row, i| (cout @topic, i; p row) unless row == []}
|
75
|
+
STDIN.gets
|
76
|
+
end
|
77
|
+
|
78
|
+
def receive(data_handle, mode = :collect)
|
79
|
+
$mode = mode
|
70
80
|
start = Time.now
|
71
81
|
|
72
82
|
@offset = 0
|
73
83
|
@pos = 0 #; @c=0; @r=0
|
74
84
|
|
75
|
-
@data,
|
85
|
+
@data, total_size = dde_get_data(data_handle) #dde_access_data(dde_handle)
|
86
|
+
p @data.get_bytes(0, total_size) if $mode == :debug
|
87
|
+
|
76
88
|
return nil unless @data && # DDE data is present at given dde_handle
|
77
89
|
read_int == TDT_TABLE && # and, first data block is tdtTable
|
78
90
|
read_int == 4 # and, its length is 4 bytes
|
@@ -81,40 +93,42 @@ module DDE
|
|
81
93
|
@col = read_int
|
82
94
|
return nil unless @row != 0 && @col != 0 # Make sure nonzero row and col
|
83
95
|
|
96
|
+
p "data set size #{total_size}, row #{@row}, col #{@col}" if $mode == :debug
|
97
|
+
@strings = @floats = @flints = @ints = @blanks = @skips = @bools = @errors = 0
|
98
|
+
|
84
99
|
@table = Array.new(@row){||Array.new}
|
85
100
|
|
86
|
-
while @offset
|
101
|
+
while @offset <= total_size-4 # Need at least 4 bytes ahead to read data type and size
|
87
102
|
type = read_int # Next data field(s) type
|
88
|
-
|
103
|
+
size = read_int # Next data field(s) length in bytes
|
89
104
|
|
90
|
-
|
105
|
+
p "type #{TDT_TYPES[type]}, cb #{size}, row #{@pos/@col}, col #{@pos%@col}" if $mode == :debug
|
91
106
|
case type
|
92
107
|
when TDT_STRING # Strings, length byte followed by chars, no zero termination
|
93
|
-
field_end = @offset +
|
108
|
+
field_end = @offset + size
|
94
109
|
while @offset < field_end do
|
95
110
|
length = read_char
|
96
111
|
self.table = @data.get_bytes(@offset, length) #read_bytes(length)#.force_encoding('CP1251').encode('CP866')
|
97
112
|
@offset += length
|
113
|
+
@strings += 1
|
98
114
|
end
|
99
115
|
when TDT_FLOAT # Float, 8 bytes (used to represent Integers too in Quik!)
|
100
|
-
(
|
101
|
-
#
|
102
|
-
# end
|
103
|
-
float_or_int = @data.get_float64(@offset)
|
116
|
+
(size/8).times do
|
117
|
+
float_or_int = @data.get_float64(@offset) # self.table = read_double
|
104
118
|
@offset += 8
|
105
119
|
int = float_or_int.round
|
106
|
-
self.table = float_or_int == int ? int : float_or_int
|
120
|
+
self.table = float_or_int == int ? (@flints += 1; int) : (@floats +=1; float_or_int)
|
107
121
|
end
|
108
122
|
when TDT_BLANK # Number of blank cells, 2 bytes
|
109
|
-
(
|
123
|
+
(size/2).times { read_int.times { self.table = ""; @blanks += 1 } }
|
110
124
|
when TDT_SKIP # Number of cells to skip, 2 bytes - in Quik, it means that these cells contain 0
|
111
|
-
(
|
125
|
+
(size/2).times { read_int.times { self.table = 0; @skips += 1 } }
|
112
126
|
when TDT_INT # Int, 2 bytes
|
113
|
-
(
|
127
|
+
(size/2).times { self.table = read_int; @ints += 1 }
|
114
128
|
when TDT_BOOL # Bool, 2 bytes 0/1
|
115
|
-
(
|
129
|
+
(size/2).times { self.table = read_int == 0; @bools += 1 }
|
116
130
|
when TDT_ERROR # Error enum, 2 bytes
|
117
|
-
(
|
131
|
+
(size/2).times { self.table = "Error:#{read_int}"; @errors += 1 }
|
118
132
|
else
|
119
133
|
cout "Type: #{type}, #{TDT_TYPES[type]}"
|
120
134
|
return nil
|
@@ -124,6 +138,7 @@ module DDE
|
|
124
138
|
@time = Time.now - start
|
125
139
|
@total_time += @time
|
126
140
|
@total_records += @row
|
141
|
+
#dde_unaccess_data(dde_handle)
|
127
142
|
true # Data acquisition successful
|
128
143
|
end
|
129
144
|
|
@@ -131,6 +146,11 @@ module DDE
|
|
131
146
|
cout "Last: #{@row} in #{@time} s(#{@time/@row} s/rec), total: #{@total_records} in #{
|
132
147
|
@total_time} s(#{@total_time/@total_records} s/rec)\n"
|
133
148
|
end
|
149
|
+
|
150
|
+
def formats
|
151
|
+
cout "Strings #{@strings} Floats #{@floats} FlInts #{@flints} Ints #{@ints} Blanks #{
|
152
|
+
@blanks} Skips #{@skips} Bools #{@bools} Errors #{@errors}\n"
|
153
|
+
end
|
134
154
|
|
135
155
|
def read_char
|
136
156
|
@offset += 1
|
@@ -161,7 +181,7 @@ module DDE
|
|
161
181
|
# @r+=1
|
162
182
|
# end
|
163
183
|
# todo: Add code for (sync!) publishing of assembled data row here (bunny? rosetta_queue?)
|
164
|
-
|
184
|
+
p value if $mode == :debug
|
165
185
|
@table[@pos/@col][@pos%@col] = value
|
166
186
|
@pos += 1
|
167
187
|
end
|
data/spec/dde/app_shared.rb
CHANGED
@@ -16,7 +16,7 @@ module DDETest
|
|
16
16
|
@app.init_flags.should == APPCLASS_STANDARD
|
17
17
|
@app.dde_active?.should == true
|
18
18
|
end unless described_class == DDE::Monitor
|
19
|
-
|
19
|
+
|
20
20
|
describe '#start_dde' do
|
21
21
|
it 'starts DDE with callback and default init_flags' do
|
22
22
|
res = @app.start_dde {|*args|}
|
data/spec/dde/app_spec.rb
CHANGED
data/spec/dde/client_spec.rb
CHANGED
@@ -3,32 +3,6 @@ require File.expand_path(File.dirname(__FILE__) + '/app_shared')
|
|
3
3
|
|
4
4
|
module DDETest
|
5
5
|
|
6
|
-
def start_callback_recorder
|
7
|
-
@client_calls = []
|
8
|
-
@server_calls = []
|
9
|
-
@client = DDE::Client.new {|*args| @client_calls << extract_values(*args); 1}
|
10
|
-
@server = DDE::Server.new do |*args|
|
11
|
-
@server_calls << extract_values(*args)
|
12
|
-
#puts "#{Time.now.strftime('%T.%6N')} #{extract_values(*args)}"
|
13
|
-
DDE_FACK
|
14
|
-
end
|
15
|
-
@server.start_service('service')
|
16
|
-
end
|
17
|
-
|
18
|
-
def stop_callback_recorder
|
19
|
-
@client.stop_conversation if @client.conversation_active?
|
20
|
-
#@client.stop_dde if @client.dde_active?
|
21
|
-
@server.stop_service if @server.service_active?
|
22
|
-
@server.stop_dde if @server.dde_active?
|
23
|
-
end
|
24
|
-
|
25
|
-
def extract_values(type, format, conv, hsz1, hsz2, data, data1, data2)
|
26
|
-
[Win::DDE::TYPES[type], format, conv,
|
27
|
-
dde_query_string(@client.id, hsz1),
|
28
|
-
dde_query_string(@client.id, hsz2),
|
29
|
-
data, data1, data2]
|
30
|
-
end
|
31
|
-
|
32
6
|
describe DDE::Client do
|
33
7
|
before(:each){ @client = DDE::Client.new }
|
34
8
|
after(:each){ @client.stop_dde if @client.dde_active?}
|
@@ -103,7 +77,7 @@ module DDETest
|
|
103
77
|
it 'initiates XTYP_CONNECT transaction to service`s callback' do
|
104
78
|
@client.start_conversation 'service', 'topic'
|
105
79
|
|
106
|
-
@server_calls.first[0].should ==
|
80
|
+
@server_calls.first[0].should == :XTYP_CONNECT
|
107
81
|
@server_calls.first[3].should == @client.topic
|
108
82
|
@server_calls.first[4].should == @client.service
|
109
83
|
end
|
@@ -112,7 +86,7 @@ module DDETest
|
|
112
86
|
@client.start_conversation 'service', 'topic'
|
113
87
|
|
114
88
|
# p @server_calls, @client_calls # ?????????? No XTYP_DISCONNECT ? Why ?
|
115
|
-
@server_calls[1][0].should ==
|
89
|
+
@server_calls[1][0].should == :XTYP_CONNECT_CONFIRM
|
116
90
|
@server_calls[1][3].should == @client.topic
|
117
91
|
@server_calls[1][4].should == @client.service
|
118
92
|
end
|
@@ -157,9 +131,7 @@ module DDETest
|
|
157
131
|
|
158
132
|
context 'with active (initialized) DDE AND existing DDE server supporting "service" topic' do
|
159
133
|
before(:each ){start_callback_recorder}
|
160
|
-
after(:each )
|
161
|
-
stop_callback_recorder
|
162
|
-
end
|
134
|
+
after(:each ){stop_callback_recorder}
|
163
135
|
|
164
136
|
it 'fails to stop conversation' do
|
165
137
|
lambda{@client.stop_conversation}.
|
@@ -193,12 +165,36 @@ module DDETest
|
|
193
165
|
pending
|
194
166
|
@client.stop_conversation
|
195
167
|
p @server_calls, @client_calls # ?????????? No XTYP_DISCONNECT ? Why ?
|
196
|
-
@server_calls.last[0].should ==
|
168
|
+
@server_calls.last[0].should == :XTYP_DISCONNECT
|
197
169
|
end
|
198
170
|
|
199
171
|
end # context 'conversation already started'
|
200
172
|
|
201
173
|
end # context 'with active (initialized) DDE AND existing DDE server supporting "service" topic'
|
202
174
|
end # describe '#stop_conversation'
|
175
|
+
|
176
|
+
describe '#send_data' do
|
177
|
+
context 'with active (initialized) DDE AND existing DDE server supporting "service" topic' do
|
178
|
+
before(:each )do
|
179
|
+
start_callback_recorder do |*args|
|
180
|
+
@server_calls << extract_values(*args)
|
181
|
+
if args[0] == XTYP_POKE
|
182
|
+
@data, @size = dde_get_data(args[5])
|
183
|
+
end
|
184
|
+
DDE_FACK
|
185
|
+
end
|
186
|
+
@client.start_conversation 'service', 'topic'
|
187
|
+
end
|
188
|
+
after(:each ){stop_callback_recorder}
|
189
|
+
|
190
|
+
it 'sends data to server' do
|
191
|
+
@client.send_data TEST_STRING, CF_TEXT, "item"
|
192
|
+
@server_calls.last[0].should == :XTYP_POKE
|
193
|
+
@data.get_bytes(0, @size).rstrip.should == TEST_STRING
|
194
|
+
end
|
195
|
+
|
196
|
+
end # context 'with active (initialized) DDE'
|
197
|
+
end # describe #send_data
|
198
|
+
|
203
199
|
end # describe DDE::Client
|
204
200
|
end
|
data/spec/dde/monitor_spec.rb
CHANGED
@@ -3,11 +3,15 @@ require File.expand_path(File.dirname(__FILE__) + '/app_shared')
|
|
3
3
|
|
4
4
|
module DDETest
|
5
5
|
|
6
|
+
describe DDE::Monitor, " in general" do
|
7
|
+
it_should_behave_like "DDE App"
|
8
|
+
end
|
9
|
+
|
6
10
|
describe DDE::Monitor do
|
7
|
-
before(:each){
|
8
|
-
after(:each){ @monitor.stop_dde }
|
11
|
+
before(:each){ }
|
12
|
+
after(:each){ @monitor.stop_dde if @monitor.dde_active? }
|
13
|
+
# SEEMS LIKE IT DOESN'T stop system from sending :XTYP_MONITOR transactions to already dead callback :(
|
9
14
|
|
10
|
-
it_should_behave_like "DDE App"
|
11
15
|
|
12
16
|
it 'starts without constructor parameters' do
|
13
17
|
@monitor = DDE::Monitor.new
|
@@ -26,69 +30,5 @@ module DDETest
|
|
26
30
|
MF_SENDMSGS # monitor sent DDE messages
|
27
31
|
end
|
28
32
|
|
29
|
-
# context 'with existing DDE clients and server supporting "service" topic' do
|
30
|
-
# before(:each )do
|
31
|
-
# @client_calls = []
|
32
|
-
# @server_calls = []
|
33
|
-
# @client = DDE::Client.new {|*args| @client_calls << args; 1}
|
34
|
-
# @server = DDE::Server.new {|*args| @server_calls << args; 1}
|
35
|
-
# @server.start_service('service')
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# it 'starts new conversation if DDE is already activated' do
|
39
|
-
# res = @client.start_conversation 'service', 'topic'
|
40
|
-
# res.should == true
|
41
|
-
# @client.conversation_active?.should == true
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# it 'sets @conversation, @service and @topic attributes' do
|
45
|
-
# @client.start_conversation 'service', 'topic'
|
46
|
-
#
|
47
|
-
# @client.conversation.should be_an Integer
|
48
|
-
# @client.conversation.should_not == 0
|
49
|
-
# @client.service.should be_a DDE::DdeString
|
50
|
-
# @client.service.should == 'service'
|
51
|
-
# @client.service.name.should == 'service'
|
52
|
-
# @client.conversation.should be_an Integer
|
53
|
-
# @client.conversation.should_not == 0
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# it 'initiates XTYP_CONNECT transaction to service`s callback' do
|
57
|
-
# @client.start_conversation 'service', 'topic'
|
58
|
-
#
|
59
|
-
# @server_calls.first[0].should == XTYP_CONNECT
|
60
|
-
# @server_calls.first[3].should == @client.topic.handle
|
61
|
-
# @server_calls.first[4].should == @client.service.handle
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
# it 'if server confirms connect, XTYP_CONNECT_CONFIRM transaction to service`s callback follows' do
|
65
|
-
# @client.start_conversation 'service', 'topic'
|
66
|
-
#
|
67
|
-
# @server_calls[1][0].should == XTYP_CONNECT_CONFIRM
|
68
|
-
# @server_calls[1][3].should == @client.topic.handle
|
69
|
-
# @server_calls[1][4].should == @client.service.handle
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# it 'client`s callback receives no transactions' do
|
73
|
-
# @client.start_conversation 'service', 'topic'
|
74
|
-
#
|
75
|
-
# p @server_calls, @client.service.handle, @client.topic.handle, @client.conversation
|
76
|
-
# @client_calls.should == []
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
# it 'fails if another conversation is already in progress' do
|
80
|
-
# @client.start_conversation 'service', 'topic'
|
81
|
-
#
|
82
|
-
# lambda{@client.start_conversation 'service1', 'topic1'}.
|
83
|
-
# should raise_error /Another conversation already established/
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# it 'fails to start conversation on unsupported service' do
|
87
|
-
# lambda{@client.start_conversation('not_a_service', 'topic')}.
|
88
|
-
# should raise_error /A client`s attempt to establish a conversation has failed/
|
89
|
-
# @client.conversation_active?.should == false
|
90
|
-
# end
|
91
|
-
#
|
92
|
-
# end
|
93
33
|
end
|
94
34
|
end
|
data/spec/dde/server_shared.rb
CHANGED
@@ -5,78 +5,68 @@ module DDETest
|
|
5
5
|
|
6
6
|
it_should_behave_like "DDE App"
|
7
7
|
|
8
|
-
|
9
|
-
@server.
|
10
|
-
@server.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@server.service.should == nil
|
21
|
-
@server.service_active?.should == false
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#start_service' do
|
25
|
-
|
26
|
-
context 'with inactive (uninitialized) DDE:' do
|
27
|
-
it 'with attached block, initializes DDE and starts new service' do
|
28
|
-
@server.start_service('myservice') {|*args|}.should be_true
|
29
|
-
|
30
|
-
@server.service.should be_a DDE::DdeString
|
31
|
-
@server.service.should == 'myservice'
|
32
|
-
@server.service.name.should == 'myservice'
|
33
|
-
@server.service.handle.should be_an Integer
|
34
|
-
@server.service.handle.should_not == 0
|
35
|
-
@server.service_active?.should == true
|
36
|
-
end
|
8
|
+
context 'specific to Servers:' do
|
9
|
+
before(:each ){ @server = described_class.new {|*args|}}
|
10
|
+
after(:each ){ @server.stop_dde if @server.dde_active?}
|
11
|
+
|
12
|
+
it 'new with attached callback block creates Server and activates DDEML, but does not start service' do
|
13
|
+
@server = described_class.new {|*args|}
|
14
|
+
@server.id.should be_an Integer
|
15
|
+
@server.id.should_not == 0
|
16
|
+
@server.dde_active?.should == true
|
17
|
+
@server.service.should == nil
|
18
|
+
@server.service_active?.should == false
|
19
|
+
end
|
37
20
|
|
38
|
-
|
39
|
-
res = @server.start_service('myservice') {|*args|}
|
40
|
-
res.should == @server
|
41
|
-
end
|
21
|
+
describe '#start_service' do
|
42
22
|
|
43
|
-
|
23
|
+
context 'with inactive (uninitialized) DDE:' do
|
24
|
+
it 'with attached block, initializes DDE and starts new service' do
|
25
|
+
@server.start_service('myservice') {|*args|}.should be_true
|
44
26
|
|
45
|
-
|
46
|
-
|
27
|
+
@server.service.should be_a DDE::DdeString
|
28
|
+
@server.service.should == 'myservice'
|
29
|
+
@server.service.name.should == 'myservice'
|
30
|
+
@server.service.handle.should be_an Integer
|
31
|
+
@server.service.handle.should_not == 0
|
32
|
+
@server.service_active?.should == true
|
33
|
+
end
|
47
34
|
|
48
|
-
|
49
|
-
|
50
|
-
|
35
|
+
it 'returns self if success (allows method chain)' do
|
36
|
+
res = @server.start_service('myservice') {|*args|}
|
37
|
+
res.should == @server
|
38
|
+
end
|
39
|
+
end # context 'with inactive (uninitialized) DDE:'
|
51
40
|
|
52
|
-
|
53
|
-
@server.service.should == 'myservice'
|
54
|
-
@server.service.name.should == 'myservice'
|
55
|
-
@server.service.handle.should be_an Integer
|
56
|
-
@server.service.handle.should_not == 0
|
57
|
-
end
|
41
|
+
context 'with active (initialized) DDE:' do
|
58
42
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
43
|
+
it 'starts new service with given name' do
|
44
|
+
res = @server.start_service 'myservice'
|
45
|
+
res.should be_true
|
63
46
|
|
64
|
-
|
65
|
-
|
47
|
+
@server.service.should be_a DDE::DdeString
|
48
|
+
@server.service.should == 'myservice'
|
49
|
+
@server.service.name.should == 'myservice'
|
50
|
+
@server.service.handle.should be_an Integer
|
51
|
+
@server.service.handle.should_not == 0
|
52
|
+
end
|
66
53
|
|
67
|
-
|
54
|
+
it 'fails to starts new service if name is not a String' do
|
55
|
+
lambda{@server.start_service(11)}.should raise_error DDE::Errors::ServiceError
|
56
|
+
@server.service_active?.should == false
|
57
|
+
end
|
58
|
+
end # context 'with active (initialized) DDE:'
|
59
|
+
end # describe '#start_service'
|
68
60
|
|
69
|
-
|
70
|
-
|
71
|
-
|
61
|
+
describe '#stop_service' do
|
62
|
+
context 'with inactive (uninitialized) DDE:' do
|
63
|
+
it 'fails to stop service' do
|
64
|
+
lambda{@server.stop_service}.should raise_error DDE::Errors::ServiceError
|
65
|
+
end
|
72
66
|
end
|
73
|
-
end
|
74
67
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
context 'with already registered DDE service: "myservice"' do
|
79
|
-
before(:each){ @server.start_service('myservice')}
|
68
|
+
context 'with active (initialized) DDE: and already registered DDE service: "myservice"' do
|
69
|
+
before(:each){ @server = described_class.new {|*args|}; @server.start_service('myservice')}
|
80
70
|
after(:each){ @server.stop_service if @server.service_active?}
|
81
71
|
|
82
72
|
it 'stops previously registered service' do
|
@@ -95,10 +85,8 @@ module DDETest
|
|
95
85
|
it 'returns self if success (allows method chain)' do
|
96
86
|
@server.stop_service.should == @server
|
97
87
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
103
|
-
end
|
88
|
+
end # context 'with active (initialized) DDE: and already registered DDE service: "myservice"'
|
89
|
+
end # describe '#stop_service'
|
90
|
+
end # context 'specific to Servers:'
|
91
|
+
end # shared_examples_for "DDE Server"
|
104
92
|
end
|
data/spec/dde/server_spec.rb
CHANGED
@@ -3,6 +3,10 @@ require File.expand_path(File.dirname(__FILE__) + '/server_shared')
|
|
3
3
|
|
4
4
|
module DDETest
|
5
5
|
|
6
|
+
describe DDE::Server, ' in general:' do
|
7
|
+
it_should_behave_like "DDE Server"
|
8
|
+
end
|
9
|
+
|
6
10
|
describe DDE::Server do
|
7
11
|
before(:each ){ @server = DDE::Server.new }
|
8
12
|
after(:each) do
|
@@ -10,7 +14,12 @@ module DDETest
|
|
10
14
|
@server.stop_dde if @server.dde_active?
|
11
15
|
end
|
12
16
|
|
13
|
-
|
17
|
+
it 'new without parameters creates Server but does not activate DDEML or start service' do
|
18
|
+
@server.id.should == nil
|
19
|
+
@server.service.should == nil
|
20
|
+
@server.dde_active?.should == false
|
21
|
+
@server.service_active?.should == false
|
22
|
+
end
|
14
23
|
|
15
24
|
describe '#start_service' do
|
16
25
|
|
@@ -23,8 +32,6 @@ module DDETest
|
|
23
32
|
lambda{@server.start_service('myservice')}.should raise_error DDE::Errors::ServiceError
|
24
33
|
@server.service_active?.should == false
|
25
34
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
35
|
+
end #describe '#start_service'
|
36
|
+
end # describe DDE::Server do
|
30
37
|
end
|
data/spec/dde/xl_server_spec.rb
CHANGED
@@ -3,6 +3,10 @@ require File.expand_path(File.dirname(__FILE__) + '/server_shared')
|
|
3
3
|
|
4
4
|
module DDETest
|
5
5
|
|
6
|
+
describe DDE::XlServer, ' in general:' do
|
7
|
+
it_should_behave_like "DDE Server"
|
8
|
+
end
|
9
|
+
|
6
10
|
describe DDE::XlServer do
|
7
11
|
before(:each ){ @server = DDE::XlServer.new }
|
8
12
|
after(:each) do
|
@@ -10,17 +14,15 @@ module DDETest
|
|
10
14
|
@server.stop_dde if @server.dde_active?
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@server.table.should be_an DDE::XlTable
|
17
|
-
@server.table.should be_empty
|
17
|
+
it 'new without parameters has empty data attribute' do
|
18
|
+
@server.data.should be_an DDE::XlTable
|
19
|
+
@server.data.should be_empty
|
18
20
|
end
|
19
21
|
|
20
|
-
it 'new with attached callback block
|
22
|
+
it 'new with attached callback block has empty data attribute' do
|
21
23
|
server = DDE::XlServer.new {|*args|}
|
22
|
-
@server.
|
23
|
-
@server.
|
24
|
+
@server.data.should be_an DDE::XlTable
|
25
|
+
@server.data.should be_empty
|
24
26
|
end
|
25
27
|
|
26
28
|
describe '#start_service' do
|
@@ -55,8 +57,7 @@ module DDETest
|
|
55
57
|
@server.service.handle.should be_an Integer
|
56
58
|
@server.service.handle.should_not == 0
|
57
59
|
end
|
58
|
-
end
|
60
|
+
end # context 'with active (initialized) DDE:'
|
59
61
|
end # describe '#start_service'
|
60
|
-
|
61
|
-
end
|
62
|
+
end # describe DDE::XlServer
|
62
63
|
end
|
data/spec/dde/xl_table_spec.rb
CHANGED
@@ -1,12 +1,51 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
3
|
module DDETest
|
4
|
+
|
5
|
+
DDE_DATA = "\x10\x00\x04\x00\b\x00\t\x00\x02\x00\t\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x18\x00fffff\x8Ee@\x00\x00\x00\x00\x00y\xB7@\x00\x00\x00\x00\x80b\xC1@\x02\x00\x01\x00\x00\x01\x00(\x00\x9A\x99\x99\x99\x99\x99\xB9?q=\n\xD7\xA3\x98e@)\\\x8F\xC2\xF5`e@\\\x8F\xC2\xF5(\x8Ce@H\xE1z$XLZA\x01\x00H\x00q=\n\xD7\xA3\x88e@\x00\x00\x00\x00\x80\xED\xC9@\x00\x00\x00\x00\x00\x00\x00\x00\xB8\x1E\x85\xEBQ e@{\x14\xAEG\xE1z\xF4?\xAEG\xE1z\x14\xCEe@\xA4p=\n\xD7\ve@H\xE1z\x14\xAE\x7Fe@\x00\x00\x80\x94\xC0-\aB\x01\x00H\x00ffff&\xF4\xB2@\x00\x00\x00\x00\x00P\x91@\x00\x00\x00\x00\x00\x00\x00\x00=\n\xD7\xA30\xA2\xB2@ffffff\xEE?\x00\x00\x00\x00\x00$\xB3@\x00\x00\x00\x00\x00\x9A\xB2@=\n\xD7\xA3\xF0\xE1\xB2@\x00\x00\x90\x9DEy\xF0A\x01\x00H\x00\x00\x00\x00\x00\x00\xD0m@\x00\x00\x00\x00\x00\xF9\xBE@\x00\x00\x00\x00\x00\x00\x00\x00\x9A\x99\x99\x99\x99\x99m@\xB8\x1E\x85\xEBQ\xB8\xAE?H\xE1z\x14\xAE\xFFm@\x00\x00\x00\x00\x00hm@\xECQ\xB8\x1E\x85\xC3m@\x00\x00\xC0\x8Fp\x80\xE6A\x01\x00H\x00\xCD\xCC\xCC\xCC\xCC\xBCT@\x00\x00\x00\x00\x80\xAF\xE7@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90T@{\x14\xAEG\xE1z\xA4?fffff\xE6T@\x9A\x99\x99\x99\x99YT@\x1F\x85\xEBQ\xB8\xAET@\x00\x00t\x80r<\x12B\x01\x00\b\x00\xF6(\\\x8F\xC2\n\x97@\x02\x00\b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00H\x00\x83\xC0\xCA\xA1E\xB6\xB3?\x00\x00\x00\x00 \xC8\xF1@\x00\x00\x00\x00\x00\x00\x00\x00@\xA4\xDF\xBE\x0E\x9C\xB3?\xA4p=\n\xD7\xA3\xC0?\t\xF9\xA0g\xB3\xEA\xB3?\xBAk\t\xF9\xA0g\xB3?r\xF9\x0F\xE9\xB7\xAF\xB3?\x00\x00 \xBC\xA35\xE9A"
|
6
|
+
DRAW_OUTPUT = "-----
|
7
|
+
[G]V
|
8
|
+
[G]V 172.45 6009 8901 0.1 172.77 171.03 172.38 6893920.57
|
9
|
+
[G]V 172.27 13275 0 169.01 1.28 174.44 168.37 171.99 12443980432
|
10
|
+
[G]V 4852.15 1108 0 4770.19 0.95 4900 4762 4833.94 4422130137
|
11
|
+
[G]V 238.5 7929 0 236.8 0.06 239.99 235.25 238.11 3020129406
|
12
|
+
[G]V 82.95 48508 0 82.25 0.04 83.6 81.4 82.73 19580887069
|
13
|
+
[G]V 1474.69
|
14
|
+
[G]V 0.077 72834 0 0.0766 0.13 0.0778 0.0758 0.0769 3383565793
|
15
|
+
Last: 8 in 0.0 s(0.0 s/rec), total: 8 in 0.0 s(0.0 s/rec)"
|
16
|
+
|
4
17
|
describe DDE::XlTable do
|
18
|
+
before(:each) {@data = DDE::XlTable.new}
|
19
|
+
|
20
|
+
it 'starts out empty and without topic' do
|
21
|
+
@data.should be_empty
|
22
|
+
@data.topic.should == nil
|
23
|
+
end
|
5
24
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
25
|
+
context 'with server/client pair and started conversation' do
|
26
|
+
before(:each )do
|
27
|
+
start_callback_recorder do|*args|
|
28
|
+
@server_calls << extract_values(*args)
|
29
|
+
if args[0] == XTYP_POKE
|
30
|
+
p extract_values(*args)
|
31
|
+
@data.receive(args[5]) #, :debug)
|
32
|
+
end
|
33
|
+
DDE_FACK
|
34
|
+
end
|
35
|
+
@client.start_conversation 'service', 'topic'
|
36
|
+
end
|
37
|
+
|
38
|
+
after(:each ){stop_callback_recorder}
|
39
|
+
|
40
|
+
it 'starts out empty and without topic' do
|
41
|
+
pending
|
42
|
+
@client.send_data DDE_DATA, CF_TEXT, "item"
|
43
|
+
@data.should_not be_empty
|
44
|
+
@data.topic.should == nil
|
45
|
+
@data.draw.should == nil
|
46
|
+
end
|
10
47
|
end
|
48
|
+
|
11
49
|
end
|
50
|
+
|
12
51
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,49 +1,110 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spork'
|
3
|
+
|
4
|
+
Spork.prefork do
|
5
|
+
# Loading more in this block will cause your tests to run faster. However,
|
6
|
+
# if you change any configuration or code from libraries loaded here, you'll
|
7
|
+
# need to restart spork for it take effect.
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
Spork.each_run do
|
12
|
+
# This code will be run each time you run your specs.
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
# --- Instructions ---
|
17
|
+
# - Sort through your spec_helper file. Place as much environment loading
|
18
|
+
# code that you don't normally modify during development in the
|
19
|
+
# Spork.prefork block.
|
20
|
+
# - Place the rest under Spork.each_run block
|
21
|
+
# - Any code that is left outside of the blocks will be ran during preforking
|
22
|
+
# and during each_run!
|
23
|
+
# - These instructions should self-destruct in 10 seconds. If they don't,
|
24
|
+
# feel free to delete them.
|
25
|
+
#
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
31
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
32
|
+
require 'spec'
|
33
|
+
require 'spec/autorun'
|
34
|
+
require 'dde'
|
35
|
+
|
36
|
+
# Customize RSpec with my own extensions
|
37
|
+
module SpecMacros
|
38
|
+
|
39
|
+
# wrapper for it method that extracts description from example source code, such as:
|
40
|
+
# spec { use{ function(arg1 = 4, arg2 = 'string') }}
|
41
|
+
def spec &block
|
42
|
+
it description_from(caller[0]), &block # it description_from(*block.source_location), &block
|
43
|
+
#do lambda(&block).should_not raise_error end
|
44
|
+
end
|
45
|
+
|
46
|
+
# reads description line from source file and drops external brackets like its{}, use{}
|
47
|
+
# accepts as arguments either file name and line or call stack member (caller[0])
|
48
|
+
def description_from(*args)
|
49
|
+
case args.size
|
50
|
+
when 1
|
51
|
+
file, line = args.first.scan(/\A(.*?):(\d+)/).first
|
52
|
+
when 2
|
53
|
+
file, line = args
|
54
|
+
end
|
55
|
+
File.open(file) do |f|
|
56
|
+
f.lines.to_a[line.to_i-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Spec::Runner.configure { |config| config.extend(SpecMacros) }
|
62
|
+
|
63
|
+
module DDETest
|
64
|
+
|
65
|
+
include Win::DDE
|
66
|
+
# @@monitor = DDE::Monitor.new
|
67
|
+
|
68
|
+
TEST_IMPOSSIBLE = 'Impossible'
|
69
|
+
TEST_STRING = "Data String"
|
70
|
+
|
71
|
+
def use
|
72
|
+
lambda {yield}.should_not raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
def any_block
|
76
|
+
lambda {|*args| args}
|
77
|
+
end
|
78
|
+
|
79
|
+
def start_callback_recorder(&server_block)
|
80
|
+
@client_calls = []
|
81
|
+
@server_calls = []
|
82
|
+
@client = DDE::Client.new {|*args| @client_calls << extract_values(*args); DDE_FACK}
|
83
|
+
@server = DDE::Server.new &server_block || proc {|*args| @server_calls << extract_values(*args); DDE_FACK }
|
84
|
+
@server.start_service('service')
|
85
|
+
end
|
86
|
+
|
87
|
+
def stop_callback_recorder
|
88
|
+
@client.stop_conversation if @client.conversation_active?
|
89
|
+
@server.stop_service if @server.service_active?
|
90
|
+
@server.stop_dde if @server.dde_active?
|
91
|
+
@client.stop_dde if @client.dde_active? #for some reason, need to stop @server FIRST, and @client LATER
|
92
|
+
end
|
93
|
+
|
94
|
+
def extract_values(*args)
|
95
|
+
args.map do |arg|
|
96
|
+
case arg
|
97
|
+
when 0
|
98
|
+
0
|
99
|
+
when Integer
|
100
|
+
id = @client.id if @client
|
101
|
+
id ||= @server.id if @server
|
102
|
+
dde_query_string(id, arg)\
|
103
|
+
|| Win::DDE.constants(false).inject(nil) {|res, const| arg == Win::DDE.const_get(const) ? res || const : res }\
|
104
|
+
|| arg
|
105
|
+
else
|
106
|
+
arg
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dde
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- arvicco
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-03-
|
12
|
+
date: 2010-03-23 00:00:00 +03:00
|
13
13
|
default_executable: dde_main
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|