ruddy 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/.gitignore +17 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +19 -0
- data/Rakefile +6 -0
- data/lib/dde.rb +76 -0
- data/lib/dde/constants.rb +7 -0
- data/lib/ruddy.rb +3 -0
- data/lib/ruddy/connection.rb +83 -0
- data/lib/ruddy/version.rb +3 -0
- data/ruddy.gemspec +24 -0
- data/spec/ruddy/connection_spec.rb +206 -0
- data/spec/support/fake_dde.rb +22 -0
- data/spec/support/string_pointer_matcher.rb +17 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a5472f2049ff6bfd144aeea055ab4e7bf2f28c2a
|
4
|
+
data.tar.gz: b631945110c72dbddb97b16f53a96b4aace394a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a48d3d9eb7bb0a5baa0c263675f629af983d940ad2322e6bf34035ad112ebecf1bf96d3901c73358d45494aa6f0eb359fb5a3656b54968b648282972b4a6cc86
|
7
|
+
data.tar.gz: 2cdb71ff621c0cdb7849428ce1d786569764d6542a62e42957df51e881f1f65b977f1a2cb4ea9f9a566654c1133654d03bc1ee7a4b5ed9179704f3631527d271
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Andrew Haines
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Ruddy
|
2
|
+
|
3
|
+
Basic Win32 DDE client in Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install ruddy
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Connect to a DDE server using the `Ruddy::Connection.open` method, and call `execute` on the yielded connection:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
require "ruddy"
|
15
|
+
|
16
|
+
Ruddy::Connection.open("SERVICE", "topic") do |connection|
|
17
|
+
connection.execute("command")
|
18
|
+
end
|
19
|
+
```
|
data/Rakefile
ADDED
data/lib/dde.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "ffi"
|
2
|
+
require "dde/constants"
|
3
|
+
|
4
|
+
module DDE
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib "user32"
|
7
|
+
ffi_convention :stdcall
|
8
|
+
|
9
|
+
# HDDEDATA CALLBACK DdeCallback(
|
10
|
+
# _In_ UINT uType,
|
11
|
+
# _In_ UINT uFmt,
|
12
|
+
# _In_ HCONV hconv,
|
13
|
+
# _In_ HSZ hsz1,
|
14
|
+
# _In_ HSZ hsz2,
|
15
|
+
# _In_ HDDEDATA hdata,
|
16
|
+
# _In_ ULONG_PTR dwData1,
|
17
|
+
# _In_ ULONG_PTR dwData2
|
18
|
+
# );
|
19
|
+
callback :dde_callback, [:uint, :uint, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :pointer
|
20
|
+
|
21
|
+
# UINT WINAPI DdeInitialize(
|
22
|
+
# _Inout_ LPDWORD pidInst,
|
23
|
+
# _In_ PFNCALLBACK pfnCallback,
|
24
|
+
# _In_ DWORD afCmd,
|
25
|
+
# _Reserved_ DWORD ulRes
|
26
|
+
# );
|
27
|
+
attach_function :start, :DdeInitializeA, [:pointer, :dde_callback, :uint, :uint], :uint
|
28
|
+
|
29
|
+
# BOOL WINAPI DdeUninitialize(
|
30
|
+
# _In_ DWORD idInst
|
31
|
+
# );
|
32
|
+
attach_function :stop, :DdeUninitialize, [:uint], :bool
|
33
|
+
|
34
|
+
# HSZ WINAPI DdeCreateStringHandle(
|
35
|
+
# _In_ DWORD idInst,
|
36
|
+
# _In_ LPTSTR psz,
|
37
|
+
# _In_ int iCodePage
|
38
|
+
# );
|
39
|
+
attach_function :create_string_handle, :DdeCreateStringHandleA, [:uint, :pointer, :int], :pointer
|
40
|
+
|
41
|
+
# HCONV WINAPI DdeConnect(
|
42
|
+
# _In_ DWORD idInst,
|
43
|
+
# _In_ HSZ hszService,
|
44
|
+
# _In_ HSZ hszTopic,
|
45
|
+
# _In_opt_ PCONVCONTEXT pCC
|
46
|
+
# );
|
47
|
+
attach_function :connect, :DdeConnect, [:uint, :pointer, :pointer, :pointer], :pointer
|
48
|
+
|
49
|
+
# HDDEDATA WINAPI DdeClientTransaction(
|
50
|
+
# _In_opt_ LPBYTE pData,
|
51
|
+
# _In_ DWORD cbData,
|
52
|
+
# _In_ HCONV hConv,
|
53
|
+
# _In_opt_ HSZ hszItem,
|
54
|
+
# _In_ UINT wFmt,
|
55
|
+
# _In_ UINT wType,
|
56
|
+
# _In_ DWORD dwTimeout,
|
57
|
+
# _Out_opt_ LPDWORD pdwResult
|
58
|
+
# );
|
59
|
+
attach_function :client_transaction, :DdeClientTransaction, [:pointer, :uint, :pointer, :pointer, :uint, :uint, :uint, :pointer], :pointer
|
60
|
+
|
61
|
+
# UINT WINAPI DdeGetLastError(
|
62
|
+
# _In_ DWORD idInst
|
63
|
+
# );
|
64
|
+
attach_function :last_error, :DdeGetLastError, [:uint], :uint
|
65
|
+
|
66
|
+
# BOOL WINAPI DdeFreeDataHandle(
|
67
|
+
# _In_ HDDEDATA hData
|
68
|
+
# );
|
69
|
+
attach_function :free_data_handle, :DdeFreeDataHandle, [:pointer], :bool
|
70
|
+
|
71
|
+
# BOOL WINAPI DdeFreeStringHandle(
|
72
|
+
# _In_ DWORD idInst,
|
73
|
+
# _In_ HSZ hsz
|
74
|
+
# );
|
75
|
+
attach_function :free_string_handle, :DdeFreeStringHandle, [:uint, :pointer], :bool
|
76
|
+
end
|
data/lib/ruddy.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Ruddy
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
attr_reader :service, :topic
|
5
|
+
attr_accessor :timeout
|
6
|
+
|
7
|
+
def initialize(service, topic, options = {})
|
8
|
+
@service = service
|
9
|
+
@topic = topic
|
10
|
+
@timeout = options.fetch(:timeout, 3000)
|
11
|
+
|
12
|
+
start
|
13
|
+
connect
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
@closed = true
|
18
|
+
DDE.stop(instance)
|
19
|
+
end
|
20
|
+
|
21
|
+
def closed?
|
22
|
+
@closed
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute(command)
|
26
|
+
raise IOError.new("closed connection") if closed?
|
27
|
+
|
28
|
+
buffer = FFI::MemoryPointer.from_string(command)
|
29
|
+
result = FFI::MemoryPointer.new(:uint)
|
30
|
+
|
31
|
+
data = DDE.client_transaction(buffer, buffer.size, conversation, nil, 0, DDE::XTYP_EXECUTE, timeout, result)
|
32
|
+
raise SystemCallError.new("command execution failed", DDE.last_error(instance)) if data.null?
|
33
|
+
DDE.free_data_handle(data)
|
34
|
+
|
35
|
+
return result.read_uint
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.open(*args)
|
39
|
+
connection = new(*args)
|
40
|
+
return connection unless block_given?
|
41
|
+
|
42
|
+
begin
|
43
|
+
yield connection
|
44
|
+
ensure
|
45
|
+
connection.close
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :instance, :conversation
|
52
|
+
|
53
|
+
CALLBACK = ->(*){}
|
54
|
+
|
55
|
+
def start
|
56
|
+
instance = FFI::MemoryPointer.new(:uint)
|
57
|
+
error = DDE.start(instance, CALLBACK, DDE::APPCLASS_STANDARD | DDE::APPCMD_CLIENTONLY, 0)
|
58
|
+
raise SystemCallError.new("DDE management library initialization failed", error) if error != DDE::DMLERR_NO_ERROR
|
59
|
+
@instance = instance.read_uint
|
60
|
+
end
|
61
|
+
|
62
|
+
def connect
|
63
|
+
service_handle = create_string_handle(service)
|
64
|
+
topic_handle = create_string_handle(topic)
|
65
|
+
|
66
|
+
@conversation = DDE.connect(instance, service_handle, topic_handle, nil)
|
67
|
+
|
68
|
+
free_string_handle service_handle
|
69
|
+
free_string_handle topic_handle
|
70
|
+
|
71
|
+
raise SystemCallError.new(%{could not connect to DDE service "#{service}"}) if conversation.null?
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_string_handle(string)
|
75
|
+
DDE.create_string_handle(instance, string, DDE::CP_WINANSI)
|
76
|
+
end
|
77
|
+
|
78
|
+
def free_string_handle(handle)
|
79
|
+
DDE.free_string_handle(instance, handle)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
data/ruddy.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "ruddy/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "ruddy"
|
7
|
+
gem.version = Ruddy::VERSION
|
8
|
+
gem.authors = ["Andrew Haines"]
|
9
|
+
gem.email = ["andrew@haines.org.nz"]
|
10
|
+
gem.summary = %q{Basic Win32 DDE client in Ruby}
|
11
|
+
gem.homepage = "https://github.com/haines/ruddy"
|
12
|
+
gem.license = "MIT"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_dependency "ffi", "~> 1.7.0"
|
20
|
+
|
21
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
gem.add_development_dependency "rake"
|
23
|
+
gem.add_development_dependency "rspec", "~> 2.13"
|
24
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require "ruddy/connection"
|
2
|
+
require "ffi"
|
3
|
+
|
4
|
+
require "support/fake_dde"
|
5
|
+
require "support/string_pointer_matcher"
|
6
|
+
|
7
|
+
module Ruddy
|
8
|
+
describe Connection do
|
9
|
+
describe ".new" do
|
10
|
+
it "sets the service" do
|
11
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
12
|
+
|
13
|
+
expect(connection.service).to eq "MY_SERVICE"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the topic" do
|
17
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
18
|
+
|
19
|
+
expect(connection.topic).to eq "my_topic"
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "timeout option" do
|
23
|
+
it "sets the timeout" do
|
24
|
+
connection = Connection.new("MY_SERVICE", "my_topic", timeout: 1000)
|
25
|
+
|
26
|
+
expect(connection.timeout).to eq 1000
|
27
|
+
end
|
28
|
+
|
29
|
+
it "defaults to 3 sec" do
|
30
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
31
|
+
|
32
|
+
expect(connection.timeout).to eq 3000
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "connects to the service" do
|
37
|
+
stub_instance 42
|
38
|
+
|
39
|
+
service_handle = stub("service_handle")
|
40
|
+
DDE.stub(:create_string_handle).with(42, "MY_SERVICE", DDE::CP_WINANSI).and_return(service_handle)
|
41
|
+
|
42
|
+
topic_handle = stub("topic_handle")
|
43
|
+
DDE.stub(:create_string_handle).with(42, "my_topic", DDE::CP_WINANSI).and_return(topic_handle)
|
44
|
+
|
45
|
+
DDE.should_receive(:connect).with(42, service_handle, topic_handle, nil).and_return(valid_pointer)
|
46
|
+
Connection.new("MY_SERVICE", "my_topic")
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when initializing the DDE management library fails" do
|
50
|
+
it "raises an error" do
|
51
|
+
DDE.stub start: 0x4006
|
52
|
+
expect{Connection.new("MY_SERVICE", "my_topic")}.to raise_error SystemCallError, /DDE management library initialization failed/
|
53
|
+
end
|
54
|
+
|
55
|
+
it "sets the error code" do
|
56
|
+
DDE.stub start: 0x4006
|
57
|
+
begin
|
58
|
+
Connection.new("MY_SERVICE", "my_topic")
|
59
|
+
rescue SystemCallError => error
|
60
|
+
expect(error.errno).to eq 0x4006
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the connection fails" do
|
66
|
+
it "raises an error" do
|
67
|
+
DDE.stub connect: null_pointer
|
68
|
+
expect{Connection.new("MY_SERVICE", "my_topic")}.to raise_error SystemCallError, /could not connect to DDE service "MY_SERVICE"/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#close" do
|
74
|
+
it "uninitializes the DDE management library" do
|
75
|
+
stub_instance 42
|
76
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
77
|
+
|
78
|
+
DDE.should_receive(:stop).with(42)
|
79
|
+
connection.close
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#closed?" do
|
84
|
+
it "is false initially" do
|
85
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
86
|
+
|
87
|
+
expect(connection).not_to be_closed
|
88
|
+
end
|
89
|
+
|
90
|
+
it "is true after closing" do
|
91
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
92
|
+
connection.close
|
93
|
+
|
94
|
+
expect(connection).to be_closed
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#execute" do
|
99
|
+
it "executes the given command" do
|
100
|
+
conversation = valid_pointer
|
101
|
+
DDE.stub connect: conversation
|
102
|
+
connection = Connection.new("MY_SERVICE", "my_topic", timeout: 12345)
|
103
|
+
command = "[Foo(bar)]"
|
104
|
+
|
105
|
+
DDE.should_receive(:client_transaction).with(string_pointer(command), command.length + 1, conversation, nil, 0, DDE::XTYP_EXECUTE, 12345, kind_of(FFI::MemoryPointer)).and_return(valid_pointer)
|
106
|
+
connection.execute(command)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns the result" do
|
110
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
111
|
+
DDE.stub :client_transaction do |*, result|
|
112
|
+
result.write_uint 43
|
113
|
+
end
|
114
|
+
|
115
|
+
expect(connection.execute("[Foo(bar)]")).to eq 43
|
116
|
+
end
|
117
|
+
|
118
|
+
it "frees the returned data structure" do
|
119
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
120
|
+
data = valid_pointer
|
121
|
+
DDE.stub client_transaction: data
|
122
|
+
|
123
|
+
DDE.should_receive(:free_data_handle).with(data)
|
124
|
+
connection.execute("[Foo(bar)]")
|
125
|
+
end
|
126
|
+
|
127
|
+
context "when the execution fails" do
|
128
|
+
it "raises an error" do
|
129
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
130
|
+
DDE.stub client_transaction: null_pointer
|
131
|
+
|
132
|
+
expect{connection.execute("[Foo(bar)]")}.to raise_error SystemCallError, /command execution failed/
|
133
|
+
end
|
134
|
+
|
135
|
+
it "sets the error code" do
|
136
|
+
stub_instance 42
|
137
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
138
|
+
DDE.stub(:last_error).with(42).and_return(0x4000)
|
139
|
+
DDE.stub client_transaction: null_pointer
|
140
|
+
|
141
|
+
begin
|
142
|
+
connection.execute("[Foo(bar)]")
|
143
|
+
rescue SystemCallError => error
|
144
|
+
expect(error.errno).to eq 0x4000
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when the connection is closed" do
|
150
|
+
it "raises an error" do
|
151
|
+
connection = Connection.new("MY_SERVICE", "my_topic")
|
152
|
+
connection.close
|
153
|
+
|
154
|
+
expect{connection.execute("[Foo(bar)]")}.to raise_error IOError, /closed connection/
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe ".open" do
|
160
|
+
context "with a block" do
|
161
|
+
it "yields a connection" do
|
162
|
+
yielded = false
|
163
|
+
Connection.open("MY_SERVICE", "my_topic") do |connection|
|
164
|
+
yielded = connection
|
165
|
+
end
|
166
|
+
|
167
|
+
expect(yielded).to be_a Connection
|
168
|
+
end
|
169
|
+
|
170
|
+
it "closes the connection afterwards" do
|
171
|
+
yielded = false
|
172
|
+
Connection.open("MY_SERVICE", "my_topic") do |connection|
|
173
|
+
expect(connection).not_to be_closed
|
174
|
+
yielded = connection
|
175
|
+
end
|
176
|
+
|
177
|
+
expect(yielded).to be_closed
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "without a block" do
|
182
|
+
it "returns an open connection" do
|
183
|
+
connection = Connection.open("MY_SERVICE", "my_topic")
|
184
|
+
|
185
|
+
expect(connection).to be_a Connection
|
186
|
+
expect(connection).not_to be_closed
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def stub_instance(instance)
|
192
|
+
DDE.stub :start do |pointer, *|
|
193
|
+
pointer.write_uint instance
|
194
|
+
DDE::DMLERR_NO_ERROR
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def valid_pointer
|
199
|
+
FFI::MemoryPointer.new(:uint)
|
200
|
+
end
|
201
|
+
|
202
|
+
def null_pointer
|
203
|
+
stub(null?: true)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "dde/constants"
|
2
|
+
|
3
|
+
module DDE
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def start(*)
|
7
|
+
DDE::DMLERR_NO_ERROR
|
8
|
+
end
|
9
|
+
|
10
|
+
def connect(*)
|
11
|
+
FFI::MemoryPointer.new(:uint)
|
12
|
+
end
|
13
|
+
|
14
|
+
def stop(*) end
|
15
|
+
|
16
|
+
def create_string_handle(*) end
|
17
|
+
def free_string_handle(*) end
|
18
|
+
|
19
|
+
def free_data_handle(*) end
|
20
|
+
|
21
|
+
def last_error(*) end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class StringPointerMatcher
|
2
|
+
def initialize(string)
|
3
|
+
@string = string
|
4
|
+
end
|
5
|
+
|
6
|
+
def ==(actual)
|
7
|
+
@string == actual.read_string
|
8
|
+
end
|
9
|
+
|
10
|
+
def description
|
11
|
+
"pointer to #{@string.inspect}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def string_pointer(string)
|
16
|
+
StringPointerMatcher.new(string)
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruddy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Haines
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.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: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.13'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.13'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- andrew@haines.org.nz
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/dde.rb
|
82
|
+
- lib/dde/constants.rb
|
83
|
+
- lib/ruddy.rb
|
84
|
+
- lib/ruddy/connection.rb
|
85
|
+
- lib/ruddy/version.rb
|
86
|
+
- ruddy.gemspec
|
87
|
+
- spec/ruddy/connection_spec.rb
|
88
|
+
- spec/support/fake_dde.rb
|
89
|
+
- spec/support/string_pointer_matcher.rb
|
90
|
+
homepage: https://github.com/haines/ruddy
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.0.0
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: Basic Win32 DDE client in Ruby
|
114
|
+
test_files:
|
115
|
+
- spec/ruddy/connection_spec.rb
|
116
|
+
- spec/support/fake_dde.rb
|
117
|
+
- spec/support/string_pointer_matcher.rb
|