dynarex 0.6.6 → 0.7.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 +40 -3
  2. metadata +2 -3
  3. data/lib/dynarexx.rb +0 -267
@@ -10,22 +10,37 @@ require 'builder'
10
10
  class Dynarex
11
11
  include REXML
12
12
 
13
+ #Create a new dynarex document from 1 of the following options:
14
+ #* a local file path
15
+ #* a URL
16
+ #* a schema string
17
+ # Dynarex.new 'contacts[title,description]/contact(name,age,dob)'
18
+ #* an XML string
19
+ # Dynarex.new '<contacts><summary><schema>contacts/contact(name,age,dob)</schema></summary><records/></contacts>'
20
+
13
21
  def initialize(location)
14
22
  open(location)
15
23
  end
16
24
 
25
+ # Returns the hash representation of the document summary.
26
+
17
27
  def summary
18
28
  @summary
19
29
  end
20
30
 
31
+ #Return a Hash (which can be edited) containing all records.
32
+
21
33
  def records
22
34
  @records
23
35
  end
24
36
 
37
+ #Returns a ready-only snapshot of records as a simple Hash.
25
38
  def flat_records
26
39
  @flat_records
27
40
  end
28
41
 
42
+ # Returns all records as a string format specified by the summary format_mask field.
43
+
29
44
  def to_s
30
45
  xsl_buffer =<<EOF
31
46
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
@@ -56,24 +71,27 @@ EOF
56
71
  display_xml()
57
72
  end
58
73
 
74
+ #Save the document to a local file.
75
+
59
76
  def save(filepath)
60
77
  xml = display_xml()
61
78
  File.open(filepath,'w'){|f| f.write xml}
62
79
  end
63
80
 
81
+ #Parses 1 or more lines of text to create or update existing records.
82
+
64
83
  def parse(buffer)
65
84
  i = XPath.match(@doc.root, 'records/*/attribute::id').max_by(&:value).to_s.to_i
66
85
  format_mask = XPath.first(@doc.root, 'summary/format_mask/text()').to_s
67
86
  t = format_mask.to_s.gsub(/\[!(\w+)\]/, '(.*)').sub(/\[/,'\[').sub(/\]/,'\]')
68
87
  lines = buffer.split(/\r?\n|\r(?!\n)/).map {|x|x.match(/#{t}/).captures}
69
88
  fields = format_mask.scan(/\[!(\w+)\]/).flatten.map(&:to_sym)
70
- @default_key ||= fields[0]
71
89
 
72
90
  a = lines.map do|x|
73
91
  created = Time.now.to_s
74
92
 
75
93
  h = Hash[fields.zip(x)]
76
- [h[@default_key.to_s.to_sym], {id: '', created: created, last_modified: '', body: h}]
94
+ [h[@default_key], {id: '', created: created, last_modified: '', body: h}]
77
95
  end
78
96
 
79
97
  h2 = Hash[a]
@@ -98,6 +116,10 @@ EOF
98
116
  h.each {|key, item| h.delete(key) if not h2.has_key? key}
99
117
  self
100
118
  end
119
+
120
+ #Create a record from a hash containing the field name, and the field value.
121
+ # dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
122
+ # dynarex.create name: Bob, age: 52
101
123
 
102
124
  def create(params={})
103
125
 
@@ -117,8 +139,13 @@ EOF
117
139
  @doc.root.elements['records'].add record
118
140
 
119
141
  load_records
142
+ self
120
143
  end
121
144
 
145
+ #Create a record from a string, given the dynarex document contains a format mask.
146
+ # dynarex = Dynarex.new 'contacts/contact(name,age,dob)'
147
+ # dynarex.create_from_line 'Tracy 37 15-Jun-1972'
148
+
122
149
  def create_from_line(line)
123
150
  format_mask = XPath.first(@doc.root, 'summary/format_mask/text()').to_s
124
151
  t = format_mask.to_s.gsub(/\[!(\w+)\]/, '(.*)').sub(/\[/,'\[').sub(/\]/,'\]')
@@ -128,8 +155,12 @@ EOF
128
155
  fields = format_mask.scan(/\[!(\w+)\]/).flatten.map(&:to_sym)
129
156
  h = Hash[fields.zip(a)]
130
157
  create h
158
+ self
131
159
  end
132
160
 
161
+ #Updates a record from an id and a hash containing field name and field value.
162
+ # dynarex.update 4, name: Jeff, age: 38
163
+
133
164
  def update(id, params={})
134
165
  record_name, fields = capture_fields(params)
135
166
 
@@ -139,12 +170,17 @@ EOF
139
170
  record.add_attribute('last_modified', Time.now.to_s)
140
171
 
141
172
  load_records
173
+ self
142
174
  end
143
175
 
176
+ #Delete a record.
177
+ # dyarex.delete 3 # deletes record with id 3
178
+
144
179
  def delete(id)
145
180
  node = XPath.first(@doc.root, "records/*[@id='#{id}']")
146
181
  node.parent.delete node
147
182
  load_records
183
+ self
148
184
  end
149
185
 
150
186
  private
@@ -205,7 +241,6 @@ EOF
205
241
  end
206
242
 
207
243
  @default_key = fields[0]
208
- @record_name = record_name
209
244
  @records = {}
210
245
  @flat_records = {}
211
246
 
@@ -246,6 +281,8 @@ EOF
246
281
  puts @doc.to_s
247
282
  end
248
283
 
284
+ #Returns a ready-only snapshot of records as a simple Hash.
285
+
249
286
  def flat_records_to_h
250
287
  XPath.match(@doc.root, 'records/*').map do |row|
251
288
  XPath.match(row, '*').inject({}) do |r,node|
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.6.6
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors: []
7
7
 
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-05-15 00:00:00 +01:00
12
+ date: 2010-05-16 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -22,7 +22,6 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - lib/dynarexx.rb
26
25
  - lib/dynarex.rb
27
26
  has_rdoc: true
28
27
  homepage:
@@ -1,267 +0,0 @@
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
-