dde 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|