dsx-dml 0.0.1 → 0.0.2
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 +4 -4
- data/Rakefile +9 -0
- data/dsx-dml.gemspec +1 -1
- data/lib/dsx/dml.rb +52 -30
- data/lib/dsx/dml/version.rb +1 -1
- data/lib/dsx/operation.rb +170 -0
- data/lib/dsx/writer.rb +94 -0
- data/spec/dsx/dml_spec.rb +88 -39
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c0267af52f6079d2061168946dfbfedf3fdb5d5
|
4
|
+
data.tar.gz: b667fcf06038eba5823c6d5c3fb27c226f4448ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30f256ae7964fb6409af0741443c40f567e6db6aa54672d297e851159aa65190f8976cb1869e5e8196c05ed8d044bf1ef2772c6793f63f943864a0448a218d13
|
7
|
+
data.tar.gz: 0f1c0aae389746b2d12f1eb7af8d761ca8c8c4a67df21924a8decbb369b60cdbc3913d54a0efd94d467b983498c7c26bbffe3b36452b268e1bf2e500bbddf8d1
|
data/Rakefile
CHANGED
data/dsx-dml.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.1"
|
23
23
|
spec.add_development_dependency "rspec", "~> 2.14"
|
24
24
|
|
25
25
|
spec.add_runtime_dependency "net-sftp", "~> 2.1"
|
data/lib/dsx/dml.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
require 'dsx/dml/version'
|
2
|
-
require 'net/sftp'
|
3
|
-
require 'securerandom'
|
4
|
-
require 'tmpdir'
|
5
|
-
require 'tempfile'
|
6
2
|
|
7
3
|
module Dsx
|
8
4
|
module Dml
|
9
5
|
|
10
6
|
class Zone
|
11
7
|
|
12
|
-
def initialize(location_num, udf_field_num)
|
8
|
+
def initialize(location_num, udf_field_num, writer = false)
|
13
9
|
@location_num = location_num
|
14
10
|
@udf_field_num = udf_field_num
|
11
|
+
if(writer)
|
12
|
+
@writer = writer
|
13
|
+
end
|
15
14
|
end
|
16
15
|
|
17
16
|
def use(id_num)
|
18
|
-
|
17
|
+
if(@writer)
|
18
|
+
return Changeset.new(self, id_num)
|
19
|
+
else
|
20
|
+
return Changeset.new(self, id_num, @writer)
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
24
|
def location_num
|
@@ -31,19 +34,26 @@ module Dsx
|
|
31
34
|
|
32
35
|
class Changeset
|
33
36
|
|
34
|
-
def initialize(zone, id_num)
|
37
|
+
def initialize(zone, id_num, writer = false)
|
35
38
|
@id_num = id_num
|
36
39
|
@zone = zone
|
37
40
|
@stack = []
|
41
|
+
if(writer)
|
42
|
+
@writer = writer
|
43
|
+
end
|
38
44
|
start_command
|
39
45
|
end
|
40
46
|
|
41
47
|
def table(table_name)
|
42
48
|
case table_name
|
43
|
-
when
|
44
|
-
return
|
49
|
+
when :Cards
|
50
|
+
return CardsTable.new(self, table_name)
|
51
|
+
when :Names
|
52
|
+
return NamesTable.new(self, table_name)
|
53
|
+
when 'Cards'
|
54
|
+
return CardsTable.new(self, table_name)
|
45
55
|
when 'Names'
|
46
|
-
return
|
56
|
+
return NamesTable.new(self, table_name)
|
47
57
|
else
|
48
58
|
return Table.new(self, table_name)
|
49
59
|
end
|
@@ -54,26 +64,34 @@ module Dsx
|
|
54
64
|
def to_string
|
55
65
|
@stack.join("\r")
|
56
66
|
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
to_string
|
70
|
+
end
|
71
|
+
|
72
|
+
def writer=(writer)
|
73
|
+
@writer = writer
|
74
|
+
end
|
57
75
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
76
|
+
def writer
|
77
|
+
@writer
|
78
|
+
end
|
79
|
+
|
80
|
+
def net_sftp(writer = false)
|
81
|
+
if (writer)
|
82
|
+
writer.net_sftp(to_string)
|
83
|
+
elsif (@writer)
|
84
|
+
@writer.net_sftp(to_string)
|
65
85
|
end
|
66
86
|
return self
|
67
87
|
end
|
68
88
|
|
69
89
|
# Alternative to Net::SFTP.
|
70
|
-
def curl(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
result = `curl -s -S -u #{params[:user]}:#{params[:password]} -T #{file.path} -w "okay\n" sftp://#{params[:address]}/`
|
76
|
-
file.unlink()
|
90
|
+
def curl(writer = false)
|
91
|
+
if (writer)
|
92
|
+
writer.curl(to_string)
|
93
|
+
elsif (@writer)
|
94
|
+
@writer.curl(to_string)
|
77
95
|
end
|
78
96
|
return self
|
79
97
|
end
|
@@ -118,21 +136,25 @@ module Dsx
|
|
118
136
|
def curl(params)
|
119
137
|
@changeset.curl(params)
|
120
138
|
end
|
139
|
+
|
140
|
+
def queue(data)
|
141
|
+
fields(data)
|
142
|
+
end
|
121
143
|
|
122
|
-
def write(data)
|
144
|
+
def write(data={})
|
123
145
|
fields(data)
|
124
146
|
@changeset.stack << 'W'
|
125
147
|
return self
|
126
148
|
end
|
127
149
|
|
128
|
-
def update(data)
|
150
|
+
def update(data={})
|
129
151
|
fields(data)
|
130
152
|
@changeset.stack << 'U'
|
131
153
|
return self
|
132
154
|
end
|
133
155
|
|
134
156
|
def delete
|
135
|
-
fields(data)
|
157
|
+
fields(data={})
|
136
158
|
@changeset.stack << 'D'
|
137
159
|
return self
|
138
160
|
end
|
@@ -155,7 +177,7 @@ module Dsx
|
|
155
177
|
end
|
156
178
|
|
157
179
|
|
158
|
-
class
|
180
|
+
class CardsTable < Table
|
159
181
|
|
160
182
|
def relace_code(code)
|
161
183
|
single('ReplaceCode', code)
|
@@ -182,7 +204,7 @@ module Dsx
|
|
182
204
|
end
|
183
205
|
|
184
206
|
def clear_all_acl
|
185
|
-
blank('
|
207
|
+
blank('ClearAcl')
|
186
208
|
end
|
187
209
|
|
188
210
|
def clear_all_tmp_acl
|
@@ -196,7 +218,7 @@ module Dsx
|
|
196
218
|
end
|
197
219
|
|
198
220
|
|
199
|
-
class
|
221
|
+
class NamesTable < Table
|
200
222
|
|
201
223
|
def dc
|
202
224
|
@changeset.stack << 'DC'
|
data/lib/dsx/dml/version.rb
CHANGED
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'dsx/dml/version'
|
2
|
+
require 'dsx/dml'
|
3
|
+
require 'dsx/writer'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
module Dsx
|
8
|
+
module Dml
|
9
|
+
|
10
|
+
class Operation
|
11
|
+
|
12
|
+
def initialize(details, writer = false)
|
13
|
+
initialize_details(details)
|
14
|
+
initialize_command(writer)
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def last_type=(type)
|
19
|
+
@type = type
|
20
|
+
end
|
21
|
+
|
22
|
+
def last_type
|
23
|
+
@type
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset_cards
|
27
|
+
table = @changeset.table(:Names)
|
28
|
+
table.dc
|
29
|
+
table.write
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def access_levels
|
34
|
+
return AccessLevelOp.new(self, @changeset)
|
35
|
+
end
|
36
|
+
|
37
|
+
def access_levels=(args=false)
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
def linking_level=(level)
|
42
|
+
table = @changeset.table(:Cards)
|
43
|
+
table.write({Code: @identifier, Loc: @location_num, OLL: level})
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def tmp_access_levels
|
48
|
+
return TmpAccessLevelOp.new(self, @changeset)
|
49
|
+
end
|
50
|
+
|
51
|
+
def identifier
|
52
|
+
@identifier
|
53
|
+
end
|
54
|
+
|
55
|
+
def changeset
|
56
|
+
@changeset
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
@changeset.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def initialize_command(writer=false)
|
66
|
+
@zone = (writer) ? Zone.new(@location_num, @udf_num, writer) : Zone.new(@location_num, @udf_num)
|
67
|
+
changeset = @zone.use(@identifier)
|
68
|
+
changeset.table(:Names).write(FName: @first_name,
|
69
|
+
LName: @last_name,
|
70
|
+
Company: @company)
|
71
|
+
changeset.table(:UDF).write(UdfNum: @udf_num,
|
72
|
+
UdfText: @identifier)
|
73
|
+
@changeset = changeset
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize_details(details)
|
77
|
+
if( details.key?(:location_num) &&
|
78
|
+
details.key?(:udf_num) &&
|
79
|
+
details.key?(:first_name) &&
|
80
|
+
details.key?(:last_name) &&
|
81
|
+
details.key?(:company)&&
|
82
|
+
details.key?(:identifier) )
|
83
|
+
@location_num = details[:location_num]
|
84
|
+
@udf_num = details[:udf_num]
|
85
|
+
@first_name = details[:first_name]
|
86
|
+
@last_name = details[:last_name]
|
87
|
+
@company = details[:company]
|
88
|
+
@identifier = details[:identifier]
|
89
|
+
else
|
90
|
+
raise "Operation arguments missing"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
class OpTemplate
|
97
|
+
def initialize(op, changeset)
|
98
|
+
@changeset = changeset
|
99
|
+
@op = op
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
class CardRelatedOp < OpTemplate
|
105
|
+
def initialize(op, changeset)
|
106
|
+
super(op, changeset)
|
107
|
+
@table = @changeset.table(:Cards)
|
108
|
+
@table.queue(Code: op.identifier)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
class AccessLevelOp < CardRelatedOp
|
114
|
+
|
115
|
+
def + (values)
|
116
|
+
values.each do |level|
|
117
|
+
@table.add_acl(level)
|
118
|
+
end
|
119
|
+
@table.write
|
120
|
+
@op
|
121
|
+
end
|
122
|
+
|
123
|
+
def - (values)
|
124
|
+
values.each do |level|
|
125
|
+
@table.del_acl(level)
|
126
|
+
end
|
127
|
+
@table.write
|
128
|
+
@op
|
129
|
+
end
|
130
|
+
|
131
|
+
def reset
|
132
|
+
@table.clear_all_acl
|
133
|
+
@table.write
|
134
|
+
@op
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
class TmpAccessLevelOp < CardRelatedOp
|
141
|
+
|
142
|
+
def + (values)
|
143
|
+
values.each do |level|
|
144
|
+
@table.add_tmp_acl(level)
|
145
|
+
end
|
146
|
+
@table.write
|
147
|
+
@op
|
148
|
+
end
|
149
|
+
|
150
|
+
def - (values)
|
151
|
+
values.each do |level|
|
152
|
+
@table.del_tmp_acl(level)
|
153
|
+
end
|
154
|
+
@table.write
|
155
|
+
@op
|
156
|
+
end
|
157
|
+
|
158
|
+
def reset
|
159
|
+
@table.clear_all_tmp_acl
|
160
|
+
@table.write
|
161
|
+
@op
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
data/lib/dsx/writer.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'dsx/dml/version'
|
2
|
+
require 'net/sftp'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
|
8
|
+
# @ Todo: any encrypt/decrypt functions
|
9
|
+
|
10
|
+
module Dsx
|
11
|
+
module Dml
|
12
|
+
|
13
|
+
class Writer
|
14
|
+
|
15
|
+
def initialize(params)
|
16
|
+
if(params.key?(:address) && params.key?(:user) && params.key?(:password))
|
17
|
+
@address = params[:address]
|
18
|
+
@user = params[:user]
|
19
|
+
@password = encrypt(params[:password])
|
20
|
+
@doc_label = (params.key? :doc_label) ? params[:doc_label] : 'rb_dsx_dml'
|
21
|
+
|
22
|
+
# @key = SecureRandom::uuid()
|
23
|
+
# @salt = SecureRandom::uuid()
|
24
|
+
# @vector = SecureRandom::uuid()
|
25
|
+
|
26
|
+
else
|
27
|
+
raise 'Incomplete DSX credentials'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# params: {address: server_address, user: user, password: password}
|
32
|
+
def net_sftp(string_or_object)
|
33
|
+
data = format(string_or_object)
|
34
|
+
Net::SFTP::start(@address, @user, :password => @password) do |sftp|
|
35
|
+
sftp.file.open("/^Imp_#{@doc_label}_#{Time.now.utc.to_i}_#{SecureRandom::hex(4)}.txt", 'w') do |file|
|
36
|
+
file.write data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
dynamic_return(string_or_object)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Alternative to Net::SFTP.
|
44
|
+
def curl(string_or_object)
|
45
|
+
data = format(string_or_object)
|
46
|
+
Dir.mktmpdir do |tmpdir|
|
47
|
+
file = Tempfile.new(["^Imp_#{@doc_label}_#{Time.now.utc.to_i}_", '.txt'], tmpdir)
|
48
|
+
file.write data
|
49
|
+
file.close()
|
50
|
+
result = `curl -s -S -u #{@user}:#{@password} -T #{file.path} -w "okay\n" sftp://#{@address}/`
|
51
|
+
file.unlink()
|
52
|
+
end
|
53
|
+
|
54
|
+
dynamic_return(string_or_object)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def dynamic_return (string_or_object)
|
60
|
+
if (string_or_object.is_a? String)
|
61
|
+
return this
|
62
|
+
else
|
63
|
+
return string_or_object
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def format(string_or_object)
|
68
|
+
if(string_or_object.respond_to?(:to_s))
|
69
|
+
return string_or_object.to_s()
|
70
|
+
elsif(string_or_object.respond_to?(:to_string))
|
71
|
+
return string_or_object.to_string()
|
72
|
+
else
|
73
|
+
# Really most things will respond to to_s. Might need special casing, though.
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def password
|
80
|
+
decrypt(@password)
|
81
|
+
end
|
82
|
+
|
83
|
+
def encrypt(value)
|
84
|
+
return value
|
85
|
+
end
|
86
|
+
|
87
|
+
def decrypt(value)
|
88
|
+
return value
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
data/spec/dsx/dml_spec.rb
CHANGED
@@ -1,45 +1,94 @@
|
|
1
1
|
require 'dsx/dml'
|
2
|
+
require 'dsx/writer'
|
3
|
+
require 'dsx/operation'
|
2
4
|
require 'securerandom'
|
3
5
|
|
6
|
+
def get_card_number
|
7
|
+
rand(10000000000..99999999999)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_name
|
11
|
+
'test_' + SecureRandom::hex(4)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_credentials
|
15
|
+
{address: '127.0.0.1', user: 'teset' , password: 'testing_password'}
|
16
|
+
end
|
17
|
+
|
4
18
|
describe Dsx::Dml do
|
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
|
-
|
42
|
-
|
43
|
-
|
19
|
+
describe "Creating a changset string" do
|
20
|
+
|
21
|
+
name = get_name()
|
22
|
+
number = get_card_number()
|
23
|
+
zone = Dsx::Dml::Zone.new(130, 2)
|
24
|
+
|
25
|
+
changeset = zone.use(number)
|
26
|
+
|
27
|
+
changeset.table('Names').write({
|
28
|
+
FName: name,
|
29
|
+
LName: name + "_L",
|
30
|
+
Company: 'Bio5',
|
31
|
+
Visitor: '',
|
32
|
+
Trace: '',
|
33
|
+
Notes: ''
|
34
|
+
}).table('UDF').write({
|
35
|
+
UdfNum: 2,
|
36
|
+
UdfText: number
|
37
|
+
}).table('Cards').write({
|
38
|
+
Code: number,
|
39
|
+
PIN: 1234,
|
40
|
+
StartDate: '09/15/2013',
|
41
|
+
StopDate: '04/11/2023',
|
42
|
+
NumUses: 9999
|
43
|
+
})
|
44
|
+
|
45
|
+
changeset_string = changeset.to_string
|
46
|
+
|
47
|
+
it "Should use DML compatible newlines" do
|
48
|
+
changeset_string.should include("\r")
|
49
|
+
changeset_string.should_not include("\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "Should have some properly formatted fields and values" do
|
53
|
+
changeset_string.should include("^#{name}^^^")
|
54
|
+
changeset_string.should include("^#{number}^^^")
|
55
|
+
changeset_string.should include("\rF UdfNum ^2^^^\r")
|
56
|
+
end
|
57
|
+
|
58
|
+
# writer = Dsx::Dml::Writer.new(test_credentials)
|
59
|
+
# writer.net_sftp(changeset)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "Using an operation" do
|
64
|
+
name = get_name()
|
65
|
+
op = Dsx::Dml::Operation.new(location_num: 130,
|
66
|
+
udf_num: 2,
|
67
|
+
first_name: name,
|
68
|
+
last_name: name + '_L',
|
69
|
+
company: 'Bio5',
|
70
|
+
identifier: get_card_number())
|
71
|
+
op.access_levels += ['BIO5 Test Level 1', 'BIO5 Test Level 2']
|
72
|
+
op.access_levels -= ['Master Access Level']
|
73
|
+
op.linking_level = 1
|
74
|
+
|
75
|
+
op_string = op.to_s
|
76
|
+
|
77
|
+
it "Should use DML compatible newlines" do
|
78
|
+
op_string.should include("\r")
|
79
|
+
op_string.should_not include("\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
it "Should have access level commands" do
|
83
|
+
op_string.should include("\rF AddAcl ^BIO5 Test Level 1^^^\r")
|
84
|
+
op_string.should include("\rF AddAcl ^BIO5 Test Level 2^^^\r")
|
85
|
+
op_string.should include("\rF DelAcl ^Master Access Level^^^\r")
|
86
|
+
op_string.should include("\rF Loc ^130^^^\r")
|
87
|
+
op_string.should include("\rF OLL ^1^^^\r")
|
44
88
|
end
|
89
|
+
|
90
|
+
# writer = Dsx::Dml::Writer.new(test_credentials)
|
91
|
+
# writer.curl(op.changeset)
|
92
|
+
|
93
|
+
end
|
45
94
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dsx-dml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dgsan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '10.1'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '10.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,6 +83,8 @@ files:
|
|
83
83
|
- dsx-dml.gemspec
|
84
84
|
- lib/dsx/dml.rb
|
85
85
|
- lib/dsx/dml/version.rb
|
86
|
+
- lib/dsx/operation.rb
|
87
|
+
- lib/dsx/writer.rb
|
86
88
|
- spec/dsx/dml_spec.rb
|
87
89
|
homepage: https://github.com/dgsan/dsx-dml
|
88
90
|
licenses:
|