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.
Files changed (3) hide show
  1. data/lib/dynarex.rb +42 -14
  2. data/lib/dynarexx.rb +267 -0
  3. metadata +2 -1
@@ -154,7 +154,7 @@ EOF
154
154
  end
155
155
  xml.records do
156
156
  @records.each do |k, item|
157
- xml.send(@item_name, id: item[:id], created: item[:created], \
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 open(location)
170
- if location[/^https?:\/\//] then
171
- buffer = Kernel.open(location, 'UserAgent' => 'Dynarex-Reader').read
172
- elsif location[/\</]
173
- buffer = location
174
- else
175
- buffer = File.open(location,'r').read
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
- @doc = Document.new buffer
178
- @default_key = (XPath.first(@doc.root, 'summary/default_key/text()') || \
179
- XPath.first(@doc.root, 'records/*[1]/*[1]').name).to_s.to_sym
188
+ buffer
189
+ end
180
190
 
181
- @summary = summary_to_h
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
- @item_name = XPath.first(@doc.root, 'records/*[1]').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
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
@@ -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.5.2
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: