dynarex 0.5.2 → 0.6.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.
- data/lib/dynarex.rb +42 -14
- data/lib/dynarexx.rb +267 -0
- metadata +2 -1
data/lib/dynarex.rb
CHANGED
@@ -154,7 +154,7 @@ EOF
|
|
154
154
|
end
|
155
155
|
xml.records do
|
156
156
|
@records.each do |k, item|
|
157
|
-
xml.send(@
|
157
|
+
xml.send(@record_name, id: item[:id], created: item[:created], \
|
158
158
|
last_modified: item[:last_modified]) do
|
159
159
|
item[:body].each{|name,value| xml.send name, value}
|
160
160
|
end
|
@@ -166,26 +166,54 @@ EOF
|
|
166
166
|
|
167
167
|
end
|
168
168
|
|
169
|
-
def
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
169
|
+
def dynarex_new(s)
|
170
|
+
ptrn = %r((\w+)\[?([^\]]+)?\]?\/(\w+)\(([^\)]+)\))
|
171
|
+
root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
172
|
+
summary, fields = [raw_summary || '',raw_fields].map {|x| x.split(/,/).map &:strip}
|
173
|
+
|
174
|
+
xml = Builder::XmlMarkup.new( target: buffer='', indent: 2 )
|
175
|
+
xml.instruct! :xml, version: "1.0", encoding: "UTF-8"
|
176
|
+
|
177
|
+
xml.send root_name do
|
178
|
+
xml.summary do
|
179
|
+
summary.each do |item|
|
180
|
+
xml.send item
|
181
|
+
end
|
182
|
+
xml.recordx_type 'dynarex'
|
183
|
+
xml.format_mask fields.map {|x| "[!%s]" % x}.join(' ')
|
184
|
+
xml.schema s
|
185
|
+
end
|
186
|
+
xml.records
|
176
187
|
end
|
177
|
-
|
178
|
-
|
179
|
-
XPath.first(@doc.root, 'records/*[1]/*[1]').name).to_s.to_sym
|
188
|
+
buffer
|
189
|
+
end
|
180
190
|
|
181
|
-
|
191
|
+
def open(s)
|
192
|
+
if s[/\(/] then # schema
|
193
|
+
buffer = dynarex_new s
|
194
|
+
elsif s[/^https?:\/\//] then # url
|
195
|
+
buffer = Kernel.open(s, 'UserAgent' => 'Dynarex-Reader').read
|
196
|
+
elsif s[/\</] # xml
|
197
|
+
buffer = s
|
198
|
+
else # local file
|
199
|
+
buffer = File.open(s,'r').read
|
200
|
+
end
|
201
|
+
|
202
|
+
@doc = Document.new buffer
|
182
203
|
@schema = @doc.root.text('summary/schema').to_s
|
183
|
-
load_records
|
184
204
|
@root_name = @doc.root.name
|
185
|
-
@
|
205
|
+
@summary = summary_to_h
|
206
|
+
@default_key = XPath.first(@doc.root, 'summary/default_key/text()')
|
207
|
+
|
208
|
+
if XPath.match(@doc.root, 'records/*').length > 0 then
|
209
|
+
|
210
|
+
load_records
|
211
|
+
end
|
186
212
|
end
|
187
213
|
|
188
214
|
def load_records
|
215
|
+
@default_key = (XPath.first(@doc.root, 'records/*[1]/*[1]').name).to_s.to_sym unless @default_key
|
216
|
+
@record_name = XPath.first(@doc.root, 'records/*[1]').name
|
189
217
|
@records = records_to_h
|
190
218
|
@flat_records = flat_records_to_h
|
191
219
|
end
|
data/lib/dynarexx.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# file: dynarex.rb
|
4
|
+
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'nokogiri'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'builder'
|
9
|
+
|
10
|
+
class Dynarex
|
11
|
+
include REXML
|
12
|
+
|
13
|
+
def initialize(location)
|
14
|
+
open(location)
|
15
|
+
end
|
16
|
+
|
17
|
+
def summary
|
18
|
+
@summary
|
19
|
+
end
|
20
|
+
|
21
|
+
def records
|
22
|
+
@records
|
23
|
+
end
|
24
|
+
|
25
|
+
def flat_records
|
26
|
+
@flat_records
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
xsl_buffer =<<EOF
|
31
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
32
|
+
<xsl:output encoding="UTF-8"
|
33
|
+
method="text"
|
34
|
+
indent="no"
|
35
|
+
omit-xml-declaration="yes"/>
|
36
|
+
|
37
|
+
<xsl:template match="*">
|
38
|
+
<xsl:for-each select="records/*">[!regex_values]<xsl:text>
|
39
|
+
</xsl:text>
|
40
|
+
</xsl:for-each>
|
41
|
+
</xsl:template>
|
42
|
+
</xsl:stylesheet>
|
43
|
+
EOF
|
44
|
+
|
45
|
+
format_mask = XPath.first(@doc.root, 'summary/format_mask/text()').to_s
|
46
|
+
|
47
|
+
xslt_format = format_mask.to_s.gsub(/\s(?=\[!\w+\])/,'<xsl:text> </xsl:text>').gsub(/\[!(\w+)\]/, '<xsl:value-of select="\1"/>')
|
48
|
+
xsl_buffer.sub!(/\[!regex_values\]/, xslt_format)
|
49
|
+
|
50
|
+
xslt = Nokogiri::XSLT(xsl_buffer)
|
51
|
+
out = xslt.transform(Nokogiri::XML(@doc.to_s))
|
52
|
+
out.text
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_xml
|
56
|
+
display_xml()
|
57
|
+
end
|
58
|
+
|
59
|
+
def save(filepath)
|
60
|
+
xml = display_xml()
|
61
|
+
File.open(filepath,'w'){|f| f.write xml}
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(buffer)
|
65
|
+
i = XPath.match(@doc.root, 'records/*/attribute::id').max_by(&:value).to_s.to_i
|
66
|
+
format_mask = XPath.first(@doc.root, 'summary/format_mask/text()').to_s
|
67
|
+
t = format_mask.to_s.gsub(/\[!(\w+)\]/, '(.*)').sub(/\[/,'\[').sub(/\]/,'\]')
|
68
|
+
lines = buffer.split(/\r?\n|\r(?!\n)/).map {|x|x.match(/#{t}/).captures}
|
69
|
+
fields = format_mask.scan(/\[!(\w+)\]/).flatten.map(&:to_sym)
|
70
|
+
|
71
|
+
a = lines.map do|x|
|
72
|
+
created = Time.now.to_s
|
73
|
+
|
74
|
+
h = Hash[fields.zip(x)]
|
75
|
+
[h[@default_key], {id: '', created: created, last_modified: '', body: h}]
|
76
|
+
end
|
77
|
+
|
78
|
+
h2 = Hash[a]
|
79
|
+
|
80
|
+
#replace the existing records hash
|
81
|
+
h = @records
|
82
|
+
h2.each do |key,item|
|
83
|
+
if h.has_key? key then
|
84
|
+
|
85
|
+
# overwrite the previous item and change the timestamps
|
86
|
+
h[key][:last_modified] = item[:created]
|
87
|
+
item[:body].each do |k,v|
|
88
|
+
h[key][:body][k.to_sym] = v
|
89
|
+
end
|
90
|
+
else
|
91
|
+
i += 1
|
92
|
+
item[:id] = i.to_s
|
93
|
+
h[key] = item.clone
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
h.each {|key, item| h.delete(key) if not h2.has_key? key}
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def create(params={})
|
102
|
+
|
103
|
+
record_name, fields = capture_fields(params)
|
104
|
+
record = Element.new record_name
|
105
|
+
fields.each{|k,v| record.add Element.new(k.to_s).add_text(v) if v}
|
106
|
+
|
107
|
+
ids = XPath.match(@doc.root,'records/*/attribute::id').map &:value
|
108
|
+
id = ids.empty? ? 1 : ids.max.succ
|
109
|
+
|
110
|
+
attributes = {id: id, created: Time.now.to_s, last_modified: nil}
|
111
|
+
attributes.each {|k,v| record.add_attribute(k.to_s, v)}
|
112
|
+
@doc.root.elements['records'].add record
|
113
|
+
|
114
|
+
load_records
|
115
|
+
end
|
116
|
+
|
117
|
+
def update(id, params={})
|
118
|
+
record_name, fields = capture_fields(params)
|
119
|
+
|
120
|
+
# for each field update each record field
|
121
|
+
record = XPath.first(@doc.root, "records/#{record_name}[@id=#{id.to_s}]")
|
122
|
+
fields.each {|k,v| record.elements[k.to_s].text = v if v}
|
123
|
+
record.add_attribute('last_modified', Time.now.to_s)
|
124
|
+
|
125
|
+
load_records
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete(id)
|
129
|
+
node = XPath.first(@doc.root, "records/*[@id='#{id}']")
|
130
|
+
node.parent.delete node
|
131
|
+
load_records
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def capture_fields(params)
|
137
|
+
|
138
|
+
record_name, raw_fields = @schema.match(/(\w+)\(([^\)]+)/).captures
|
139
|
+
fields = Hash[raw_fields.split(',').map{|x| [x.strip.to_sym, nil]}]
|
140
|
+
|
141
|
+
fields.keys.each {|key| fields[key] = params[key] if params.has_key? key}
|
142
|
+
[record_name, fields]
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def display_xml
|
147
|
+
|
148
|
+
xml = Builder::XmlMarkup.new( :target => buffer='', :indent => 2 )
|
149
|
+
xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
|
150
|
+
|
151
|
+
xml.send @root_name do
|
152
|
+
xml.summary do
|
153
|
+
@summary.each{|key,value| xml.send key, value}
|
154
|
+
end
|
155
|
+
xml.records do
|
156
|
+
@records.each do |k, item|
|
157
|
+
xml.send(@record_name, id: item[:id], created: item[:created], \
|
158
|
+
last_modified: item[:last_modified]) do
|
159
|
+
item[:body].each{|name,value| xml.send name, value}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
buffer
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
def dynarex_new(s)
|
170
|
+
ptrn = %r((\w+)\[?([^\]]+)?\]?\/(\w+)\(([^\)]+)\))
|
171
|
+
root_name, raw_summary, record_name, raw_fields = s.match(ptrn).captures
|
172
|
+
summary, fields = [raw_summary || '',raw_fields].map {|x| x.split(/,/).map &:strip}
|
173
|
+
|
174
|
+
xml = Builder::XmlMarkup.new( target: buffer='', indent: 2 )
|
175
|
+
xml.instruct! :xml, version: "1.0", encoding: "UTF-8"
|
176
|
+
|
177
|
+
xml.send root_name do
|
178
|
+
xml.summary do
|
179
|
+
summary.each do |item|
|
180
|
+
xml.send item
|
181
|
+
end
|
182
|
+
xml.recordx_type 'dynarex'
|
183
|
+
xml.format_mask fields.map {|x| "[!%s]" % x}.join(' ')
|
184
|
+
xml.schema s
|
185
|
+
end
|
186
|
+
xml.records
|
187
|
+
end
|
188
|
+
buffer
|
189
|
+
end
|
190
|
+
|
191
|
+
def open(s)
|
192
|
+
if s[/\(/] then # schema
|
193
|
+
buffer = dynarex_new s
|
194
|
+
elsif s[/^https?:\/\//] then # url
|
195
|
+
buffer = Kernel.open(s, 'UserAgent' => 'Dynarex-Reader').read
|
196
|
+
elsif s[/\</] # xml
|
197
|
+
buffer = s
|
198
|
+
else # local file
|
199
|
+
buffer = File.open(s,'r').read
|
200
|
+
end
|
201
|
+
|
202
|
+
@doc = Document.new buffer
|
203
|
+
@schema = @doc.root.text('summary/schema').to_s
|
204
|
+
@root_name = @doc.root.name
|
205
|
+
@summary = summary_to_h
|
206
|
+
@default_key = XPath.first(@doc.root, 'summary/default_key/text()')
|
207
|
+
|
208
|
+
if XPath.match(@doc.root, 'records/*').length > 0 then
|
209
|
+
|
210
|
+
load_records
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def load_records
|
215
|
+
@default_key = (XPath.first(@doc.root, 'records/*[1]/*[1]').name).to_s.to_sym unless @default_key
|
216
|
+
@record_name = XPath.first(@doc.root, 'records/*[1]').name
|
217
|
+
@records = records_to_h
|
218
|
+
@flat_records = flat_records_to_h
|
219
|
+
end
|
220
|
+
|
221
|
+
def display()
|
222
|
+
puts @doc.to_s
|
223
|
+
end
|
224
|
+
|
225
|
+
def flat_records_to_h
|
226
|
+
XPath.match(@doc.root, 'records/*').map do |row|
|
227
|
+
XPath.match(row, '*').inject({}) do |r,node|
|
228
|
+
r[node.name.to_s.to_sym] = node.text.to_s
|
229
|
+
r
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def records_to_h()
|
235
|
+
i = XPath.match(@doc.root, 'records/*/attribute::id').max_by(&:value).to_s.to_i
|
236
|
+
|
237
|
+
ah = XPath.match(@doc.root, 'records/*').map do |row|
|
238
|
+
|
239
|
+
created = Time.now.to_s
|
240
|
+
last_modified = ''
|
241
|
+
|
242
|
+
if row.attribute('id') then
|
243
|
+
id = row.attribute('id').value.to_s
|
244
|
+
else
|
245
|
+
i += 1; id = i.to_s
|
246
|
+
end
|
247
|
+
created = row.attribute('created').value.to_s if row.attribute('created')
|
248
|
+
last_modified = row.attribute('last_modified').value.to_s if row.attribute('last_modified')
|
249
|
+
body = XPath.match(row, '*').inject({}) do |r,node|
|
250
|
+
r[node.name.to_s.to_sym] = node.text.to_s
|
251
|
+
r
|
252
|
+
end
|
253
|
+
[body[@default_key],{id: id, created: created, last_modified: \
|
254
|
+
last_modified, body: body}]
|
255
|
+
end
|
256
|
+
Hash[*ah.flatten]
|
257
|
+
end
|
258
|
+
|
259
|
+
def summary_to_h
|
260
|
+
XPath.match(@doc.root, 'summary/*').inject({}) do |r,node|
|
261
|
+
r[node.name.to_s.to_sym] = node.text.to_s
|
262
|
+
r
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynarex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors: []
|
7
7
|
|
@@ -22,6 +22,7 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
+
- lib/dynarexx.rb
|
25
26
|
- lib/dynarex.rb
|
26
27
|
has_rdoc: true
|
27
28
|
homepage:
|