slaw 1.0.0.alpha.6 → 1.0.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 +4 -4
- data/README.md +13 -147
- data/bin/slaw +2 -1
- data/lib/slaw.rb +0 -6
- data/lib/slaw/generator.rb +2 -8
- data/lib/slaw/grammars/pl/act.treetop +10 -14
- data/lib/slaw/grammars/pl/act_text.xsl +271 -0
- data/lib/slaw/version.rb +1 -1
- data/slaw.gemspec +3 -3
- metadata +6 -17
- data/lib/slaw/act.rb +0 -452
- data/lib/slaw/bylaw.rb +0 -62
- data/lib/slaw/collection.rb +0 -60
- data/lib/slaw/lifecycle_event.rb +0 -23
- data/lib/slaw/render/html.rb +0 -70
- data/lib/slaw/render/xsl/act.xsl +0 -15
- data/lib/slaw/render/xsl/elements.xsl +0 -120
- data/lib/slaw/render/xsl/fragment.xsl +0 -16
- data/spec/act_spec.rb +0 -56
- data/spec/bylaw_spec.rb +0 -49
data/lib/slaw/version.rb
CHANGED
data/slaw.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Slaw::VERSION
|
9
9
|
spec.authors = ["Greg Kempe"]
|
10
10
|
spec.email = ["greg@kempe.net"]
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage = ""
|
11
|
+
spec.summary = "A lightweight library for using Akoma Ntoso acts in Ruby."
|
12
|
+
spec.description = "Slaw is a lightweight library for rendering and generating Akoma Ntoso acts from plain text and PDF documents."
|
13
|
+
spec.homepage = "https://github.com/longhotsummer/slaw"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slaw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Kempe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -167,9 +167,6 @@ files:
|
|
167
167
|
- Rakefile
|
168
168
|
- bin/slaw
|
169
169
|
- lib/slaw.rb
|
170
|
-
- lib/slaw/act.rb
|
171
|
-
- lib/slaw/bylaw.rb
|
172
|
-
- lib/slaw/collection.rb
|
173
170
|
- lib/slaw/extract/extractor.rb
|
174
171
|
- lib/slaw/extract/html_to_akn_text.xsl
|
175
172
|
- lib/slaw/extract/yomu_patch.rb
|
@@ -179,6 +176,7 @@ files:
|
|
179
176
|
- lib/slaw/grammars/inlines_nodes.rb
|
180
177
|
- lib/slaw/grammars/pl/act.treetop
|
181
178
|
- lib/slaw/grammars/pl/act_nodes.rb
|
179
|
+
- lib/slaw/grammars/pl/act_text.xsl
|
182
180
|
- lib/slaw/grammars/schedules.treetop
|
183
181
|
- lib/slaw/grammars/schedules_nodes.rb
|
184
182
|
- lib/slaw/grammars/tables.treetop
|
@@ -187,7 +185,6 @@ files:
|
|
187
185
|
- lib/slaw/grammars/za/act.treetop
|
188
186
|
- lib/slaw/grammars/za/act_nodes.rb
|
189
187
|
- lib/slaw/grammars/za/act_text.xsl
|
190
|
-
- lib/slaw/lifecycle_event.rb
|
191
188
|
- lib/slaw/logging.rb
|
192
189
|
- lib/slaw/namespace.rb
|
193
190
|
- lib/slaw/parse/blocklists.rb
|
@@ -195,17 +192,11 @@ files:
|
|
195
192
|
- lib/slaw/parse/cleanser.rb
|
196
193
|
- lib/slaw/parse/error.rb
|
197
194
|
- lib/slaw/parse/grammar_helpers.rb
|
198
|
-
- lib/slaw/render/html.rb
|
199
|
-
- lib/slaw/render/xsl/act.xsl
|
200
|
-
- lib/slaw/render/xsl/elements.xsl
|
201
|
-
- lib/slaw/render/xsl/fragment.xsl
|
202
195
|
- lib/slaw/schemas/akomantoso20.xsd
|
203
196
|
- lib/slaw/schemas/xml.xsd
|
204
197
|
- lib/slaw/version.rb
|
205
198
|
- lib/slaw/xml_support.rb
|
206
199
|
- slaw.gemspec
|
207
|
-
- spec/act_spec.rb
|
208
|
-
- spec/bylaw_spec.rb
|
209
200
|
- spec/extract/extractor_spec.rb
|
210
201
|
- spec/fixtures/community-fire-safety.xml
|
211
202
|
- spec/generator_spec.rb
|
@@ -218,7 +209,7 @@ files:
|
|
218
209
|
- spec/za/act_inline_spec.rb
|
219
210
|
- spec/za/act_schedules_spec.rb
|
220
211
|
- spec/za/act_table_spec.rb
|
221
|
-
homepage:
|
212
|
+
homepage: https://github.com/longhotsummer/slaw
|
222
213
|
licenses:
|
223
214
|
- MIT
|
224
215
|
metadata: {}
|
@@ -233,9 +224,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
233
224
|
version: '0'
|
234
225
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
235
226
|
requirements:
|
236
|
-
- - "
|
227
|
+
- - ">="
|
237
228
|
- !ruby/object:Gem::Version
|
238
|
-
version:
|
229
|
+
version: '0'
|
239
230
|
requirements: []
|
240
231
|
rubyforge_project:
|
241
232
|
rubygems_version: 2.6.12
|
@@ -243,8 +234,6 @@ signing_key:
|
|
243
234
|
specification_version: 4
|
244
235
|
summary: A lightweight library for using Akoma Ntoso acts in Ruby.
|
245
236
|
test_files:
|
246
|
-
- spec/act_spec.rb
|
247
|
-
- spec/bylaw_spec.rb
|
248
237
|
- spec/extract/extractor_spec.rb
|
249
238
|
- spec/fixtures/community-fire-safety.xml
|
250
239
|
- spec/generator_spec.rb
|
data/lib/slaw/act.rb
DELETED
@@ -1,452 +0,0 @@
|
|
1
|
-
module Slaw
|
2
|
-
class AknBase
|
3
|
-
include Slaw::Namespace
|
4
|
-
|
5
|
-
attr_accessor :doc
|
6
|
-
|
7
|
-
# Serialise the XML for this act, passing `args` to the Nokogiri serialiser.
|
8
|
-
# The most useful argument is usually `indent: 2` if you like your XML perdy.
|
9
|
-
#
|
10
|
-
# @return [String] serialized XML
|
11
|
-
def to_xml(*args)
|
12
|
-
@doc.to_xml(*args)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Parse the XML contained in the file-like or String object `io`
|
16
|
-
#
|
17
|
-
# @param io [String, file-like] io object or String with XML
|
18
|
-
def parse(io)
|
19
|
-
self.doc = Nokogiri::XML(io)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# A fragment is a part of a larger document and doesn't have the context associated
|
24
|
-
# with the document.
|
25
|
-
class Fragment < AknBase
|
26
|
-
alias_method :fragment, :doc
|
27
|
-
end
|
28
|
-
|
29
|
-
# An Act wraps a single {http://www.akomantoso.org/ AkomaNtoso 2.0 XML} act document in the form of a
|
30
|
-
# Nokogiri::XML::Document object.
|
31
|
-
#
|
32
|
-
# The Act object provides quick access to certain sections of the document,
|
33
|
-
# such as the metadata and the body, as well as common operations such as
|
34
|
-
# identifying whether it has been amended ({#amended?}), repealed
|
35
|
-
# ({#repealed?}) or what chapters ({#chapters}), parts ({#parts}) and
|
36
|
-
# sections ({#sections}) it contains.
|
37
|
-
class Act < AknBase
|
38
|
-
|
39
|
-
# Allow us to jump from the XML document for an act to the
|
40
|
-
# Act instance itself
|
41
|
-
@@acts = {}
|
42
|
-
|
43
|
-
# [Nokogiri::XML::Document] The underlying {Nokogiri::XML::Document} instance
|
44
|
-
attr_accessor :doc
|
45
|
-
|
46
|
-
# [Nokogiri::XML::Node] The `meta` XML node
|
47
|
-
attr_reader :meta
|
48
|
-
|
49
|
-
# [Nokogiri::XML::Node] The `body` XML node
|
50
|
-
attr_reader :body
|
51
|
-
|
52
|
-
# [String] The year this act was published
|
53
|
-
attr_reader :year
|
54
|
-
|
55
|
-
# [String] The act number in the year this act was published
|
56
|
-
attr_reader :num
|
57
|
-
|
58
|
-
# [String] The FRBR URI of this act, which uniquely identifies it globally
|
59
|
-
attr_reader :id_uri
|
60
|
-
|
61
|
-
# [String, nil] The source filename, or nil
|
62
|
-
attr_reader :filename
|
63
|
-
|
64
|
-
# [Time, nil] The mtime of when the source file was last modified
|
65
|
-
attr_reader :mtime
|
66
|
-
|
67
|
-
# [String] The underlying nature of this act, usually `act` although subclasses my override this.
|
68
|
-
attr_reader :nature
|
69
|
-
|
70
|
-
# [Nokogiri::XML::Schema] schema to validate against
|
71
|
-
attr_accessor :schema
|
72
|
-
|
73
|
-
# Get the act that wraps the document that owns this XML node
|
74
|
-
# @param node [Nokogiri::XML::Node]
|
75
|
-
# @return [Act] owning act
|
76
|
-
def self.for_node(node)
|
77
|
-
@@acts[node.document]
|
78
|
-
end
|
79
|
-
|
80
|
-
# Create a new instance, loading from `filename` if given.
|
81
|
-
# @param filename [String] filename to load XML from
|
82
|
-
def initialize(filename=nil)
|
83
|
-
self.load(filename) if filename
|
84
|
-
@schema = nil
|
85
|
-
end
|
86
|
-
|
87
|
-
# Load the XML in `filename` into this instance
|
88
|
-
# @param filename [String] filename
|
89
|
-
def load(filename)
|
90
|
-
@filename = filename
|
91
|
-
@mtime = File::mtime(@filename)
|
92
|
-
|
93
|
-
File.open(filename) { |f| parse(f) }
|
94
|
-
end
|
95
|
-
|
96
|
-
# Set the XML document backing this bylaw.
|
97
|
-
#
|
98
|
-
# @param doc [Nokogiri::XML::Document] document
|
99
|
-
def doc=(doc)
|
100
|
-
@doc = doc
|
101
|
-
@meta = @doc.at_xpath('/a:akomaNtoso/a:act/a:meta', a: NS)
|
102
|
-
@body = @doc.at_xpath('/a:akomaNtoso/a:act/a:body', a: NS)
|
103
|
-
|
104
|
-
@@acts[@doc] = self
|
105
|
-
|
106
|
-
extract_id_uri
|
107
|
-
end
|
108
|
-
|
109
|
-
# Directly set the FRBR URI of this act. This must be a well-formed URI,
|
110
|
-
# such as `/za/act/2002/2`. This will, in turn, update the {#year}, {#nature},
|
111
|
-
# {#country} and {#num} attributes.
|
112
|
-
#
|
113
|
-
# You probably don't want to use this method. Instead, set each component
|
114
|
-
# (such as {#date}) manually.
|
115
|
-
#
|
116
|
-
# @param uri [String] new URI
|
117
|
-
def id_uri=(uri)
|
118
|
-
for component, xpath in [['main', '//a:act/a:meta/a:identification'],
|
119
|
-
['schedules', '//a:component/a:doc/a:meta/a:identification']] do
|
120
|
-
ident = @doc.at_xpath(xpath, a: NS)
|
121
|
-
next if not ident
|
122
|
-
|
123
|
-
# work
|
124
|
-
ident.at_xpath('a:FRBRWork/a:FRBRthis', a: NS)['value'] = "#{uri}/#{component}"
|
125
|
-
ident.at_xpath('a:FRBRWork/a:FRBRuri', a: NS)['value'] = uri
|
126
|
-
|
127
|
-
# expression
|
128
|
-
ident.at_xpath('a:FRBRExpression/a:FRBRthis', a: NS)['value'] = "#{uri}/#{component}/eng@"
|
129
|
-
ident.at_xpath('a:FRBRExpression/a:FRBRuri', a: NS)['value'] = "#{uri}/eng@"
|
130
|
-
|
131
|
-
# manifestation
|
132
|
-
ident.at_xpath('a:FRBRManifestation/a:FRBRthis', a: NS)['value'] = "#{uri}/#{component}/eng@"
|
133
|
-
ident.at_xpath('a:FRBRManifestation/a:FRBRuri', a: NS)['value'] = "#{uri}/eng@"
|
134
|
-
end
|
135
|
-
|
136
|
-
extract_id_uri
|
137
|
-
end
|
138
|
-
|
139
|
-
# The date at which this act was first created/promulgated.
|
140
|
-
#
|
141
|
-
# @return [String] date, YYYY-MM-DD
|
142
|
-
def date
|
143
|
-
node = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRdate[@name="Generation"]', a: NS)
|
144
|
-
node && node['date']
|
145
|
-
end
|
146
|
-
|
147
|
-
# Set the date at which this act was first created/promulgated. This is usually the same
|
148
|
-
# as the publication date but this is not enforced.
|
149
|
-
#
|
150
|
-
# This also updates the {#year} of this act, which in turn updates the {#id_uri}.
|
151
|
-
#
|
152
|
-
# @param date [String] date, YYYY-MM-DD
|
153
|
-
def date=(value)
|
154
|
-
for frbr in ['FRBRWork', 'FRBRExpression'] do
|
155
|
-
@meta.at_xpath("./a:identification/a:#{frbr}/a:FRBRdate[@name=\"Generation\"]", a: NS)['date'] = value
|
156
|
-
end
|
157
|
-
|
158
|
-
self.year = value.split('-')[0]
|
159
|
-
end
|
160
|
-
|
161
|
-
# Set the year for this act. You probably want to call {#date=} instead.
|
162
|
-
#
|
163
|
-
# This will also update the {#id_uri} but will not change {#date} at all.
|
164
|
-
#
|
165
|
-
# @param year [String, Number] year
|
166
|
-
def year=(year)
|
167
|
-
@year = year.to_s
|
168
|
-
rebuild_id_uri
|
169
|
-
end
|
170
|
-
|
171
|
-
# An applicable short title for this act, either from the `FRBRalias` element
|
172
|
-
# or based on the act number and year.
|
173
|
-
# @return [String]
|
174
|
-
def title
|
175
|
-
node = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: NS)
|
176
|
-
node ? node['value'] : "Act #{num} of #{year}"
|
177
|
-
end
|
178
|
-
|
179
|
-
# Change the title of this act.
|
180
|
-
def title=(value)
|
181
|
-
node = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: NS)
|
182
|
-
unless node
|
183
|
-
node = @doc.create_element('FRBRalias')
|
184
|
-
@meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRuri', a: NS).after(node)
|
185
|
-
end
|
186
|
-
|
187
|
-
node['value'] = value
|
188
|
-
end
|
189
|
-
|
190
|
-
# Has this act been amended? This is determined by testing the `contains`
|
191
|
-
# attribute of the `act` root element.
|
192
|
-
#
|
193
|
-
# @return [Boolean]
|
194
|
-
def amended?
|
195
|
-
@doc.at_xpath('/a:akomaNtoso/a:act', a: NS)['contains'] != 'originalVersion'
|
196
|
-
end
|
197
|
-
|
198
|
-
# Get a list of {Slaw::LifecycleEvent} objects for amendment events, in date order.
|
199
|
-
# @return [Array<Slaw::LifecycleEvent>] possibly empty list of lifecycle events
|
200
|
-
def amendment_events
|
201
|
-
@meta.xpath('./a:lifecycle/a:eventRef[@type="amendment"]', a: NS).map do |event|
|
202
|
-
LifecycleEvent.new(event)
|
203
|
-
end.sort_by { |e| e.date }
|
204
|
-
end
|
205
|
-
|
206
|
-
# Mark this act as being amended by another act, either `act`
|
207
|
-
# or the details in `opts`.
|
208
|
-
#
|
209
|
-
# It is assumed that there can be only one amendment event on a particular
|
210
|
-
# date. An existing amendment on this date is overwritten.
|
211
|
-
#
|
212
|
-
# @option opts [String] :uri uri of the amending act
|
213
|
-
# @option opts [String] :title title of the amending act
|
214
|
-
# @option opts [String] :date date of the amendment (YYYY-MM-DD)
|
215
|
-
def amended_by!(act, opts={})
|
216
|
-
if act
|
217
|
-
opts[:uri] ||= act.id_uri
|
218
|
-
opts[:title] ||= act.short_title
|
219
|
-
opts[:date] ||= act.publication['date']
|
220
|
-
end
|
221
|
-
|
222
|
-
date = opts[:date]
|
223
|
-
source_id = "amendment-#{date}"
|
224
|
-
|
225
|
-
# assume we now hold a single version and not the original version
|
226
|
-
@doc.at_xpath('/a:akomaNtoso/a:act', a: NS)['contains'] = 'singleVersion'
|
227
|
-
|
228
|
-
# add the lifecycle event
|
229
|
-
lifecycle = @meta.at_xpath('./a:lifecycle', a: NS)
|
230
|
-
if not lifecycle
|
231
|
-
lifecycle = @doc.create_element('lifecycle', source: "#this")
|
232
|
-
@meta.at_xpath('./a:publication', a: NS).after(lifecycle)
|
233
|
-
end
|
234
|
-
|
235
|
-
event = lifecycle.at_xpath('./a:eventRef[@date="' + date + '"][@type="amendment"]', a: NS)
|
236
|
-
if event
|
237
|
-
# clear up old event
|
238
|
-
src = @doc.at_css(event['source'])
|
239
|
-
src.remove if src
|
240
|
-
else
|
241
|
-
# new event
|
242
|
-
event = @doc.create_element('eventRef', type: 'amendment')
|
243
|
-
lifecycle << event
|
244
|
-
end
|
245
|
-
|
246
|
-
event['date'] = date
|
247
|
-
event['id'] = "amendment-event-#{date}"
|
248
|
-
event['source'] = '#' + source_id
|
249
|
-
|
250
|
-
# add reference
|
251
|
-
ref = @doc.create_element('passiveRef',
|
252
|
-
id: source_id,
|
253
|
-
href: opts[:uri],
|
254
|
-
showAs: opts[:title])
|
255
|
-
|
256
|
-
@meta.at_xpath('./a:references/a:TLCTerm', a: NS).before(ref)
|
257
|
-
end
|
258
|
-
|
259
|
-
# Does this Act have parts?
|
260
|
-
# @return [Boolean]
|
261
|
-
def parts?
|
262
|
-
!parts.empty?
|
263
|
-
end
|
264
|
-
|
265
|
-
# Top-level parts of this act. Parts inside chapters are ignored.
|
266
|
-
# @return [Array<Nokogiri::XML::Node>] part nodes
|
267
|
-
def parts
|
268
|
-
@body.xpath('./a:part', a: NS)
|
269
|
-
end
|
270
|
-
|
271
|
-
# Does this Act have chapters?
|
272
|
-
# @return [Boolean]
|
273
|
-
def chapters?
|
274
|
-
!chapters.empty?
|
275
|
-
end
|
276
|
-
|
277
|
-
# Top-level chapters of this act. Chapters inside parts are ignored.
|
278
|
-
# @return [Array<Nokogiri::XML::Node>] chapter nodes
|
279
|
-
def chapters
|
280
|
-
@body.xpath('./a:chapter', a: NS)
|
281
|
-
end
|
282
|
-
|
283
|
-
# Sections of this act
|
284
|
-
# @return [Array<Nokogiri::XML::Node>] section nodes
|
285
|
-
def sections
|
286
|
-
@body.xpath('.//a:section', a: NS)
|
287
|
-
end
|
288
|
-
|
289
|
-
# The primary definitions section of this act, identified by
|
290
|
-
# either an `id` of `definitions` or the first section with a heading
|
291
|
-
# of `Definitions`.
|
292
|
-
#
|
293
|
-
# @return [Nokogiri::XML::Node, nil] definitions node or nil
|
294
|
-
def definitions
|
295
|
-
# try looking for the definition list
|
296
|
-
defn = @body.at_css('#definitions')
|
297
|
-
return defn.parent if defn
|
298
|
-
|
299
|
-
# try looking for the heading
|
300
|
-
defn = @body.at_xpath('.//a:section/a:heading[text() = "Definitions"]', a: NS)
|
301
|
-
return defn.parent if defn
|
302
|
-
|
303
|
-
nil
|
304
|
-
end
|
305
|
-
|
306
|
-
# An act can contain schedules, additional (generally free-form) documents
|
307
|
-
# that are addendums to the the main body. A definition element must be
|
308
|
-
# part of a separate `component` and have a `doc` element with a name attribute
|
309
|
-
# of `schedules`.
|
310
|
-
#
|
311
|
-
# @return [Nokogiri::XML::Node, nil] schedules document node
|
312
|
-
def schedules
|
313
|
-
@doc.at_xpath('/a:akomaNtoso/a:components/a:component/a:doc[@name="schedules"]/a:mainBody', a: NS)
|
314
|
-
end
|
315
|
-
|
316
|
-
# Get a map from term ids to `[term, defn]` pairs,
|
317
|
-
# where `term+ is the plain text term and `defn` is
|
318
|
-
# the {Nokogiri::XML::Node} containing the definition.
|
319
|
-
#
|
320
|
-
# @return {String => List(String, Nokogiri::XML::Node)} map from strings to `[term, definition]` pairs
|
321
|
-
def term_definitions
|
322
|
-
terms = {}
|
323
|
-
|
324
|
-
@meta.xpath('a:references/a:TLCTerm', a: NS).each do |node|
|
325
|
-
# <TLCTerm id="term-affected_land" href="/ontology/term/this.eng.affected_land" showAs="affected land"/>
|
326
|
-
|
327
|
-
# find the point with id 'def-term-foo'
|
328
|
-
defn = @body.at_xpath(".//*[@id='def-#{node['id']}']", a: NS)
|
329
|
-
next unless defn
|
330
|
-
|
331
|
-
terms[node['id']] = [node['showAs'], defn]
|
332
|
-
end
|
333
|
-
|
334
|
-
terms
|
335
|
-
end
|
336
|
-
|
337
|
-
# Returns the publication element, if any.
|
338
|
-
#
|
339
|
-
# @return [Nokogiri::XML::Node, nil]
|
340
|
-
def publication
|
341
|
-
@meta.at_xpath('./a:publication', a: NS)
|
342
|
-
end
|
343
|
-
|
344
|
-
# Update the publication details of the act. All elements are optional.
|
345
|
-
#
|
346
|
-
# @option details [String] :name name of the publication
|
347
|
-
# @option details [String] :number publication number
|
348
|
-
# @option details [String] :date date of publication (YYYY-MM-DD)
|
349
|
-
def published!(details)
|
350
|
-
node = @meta.at_xpath('./a:publication', a: NS)
|
351
|
-
unless node
|
352
|
-
node = @doc.create_element('publication')
|
353
|
-
@meta.at_xpath('./a:identification', a: NS).after(node)
|
354
|
-
end
|
355
|
-
|
356
|
-
node['showAs'] = details[:name] if details.has_key? :name
|
357
|
-
node['name'] = details[:name] if details.has_key? :name
|
358
|
-
node['date'] = details[:date] if details.has_key? :date
|
359
|
-
node['number'] = details[:number] if details.has_key? :number
|
360
|
-
end
|
361
|
-
|
362
|
-
# Has this by-law been repealed?
|
363
|
-
#
|
364
|
-
# @return [Boolean]
|
365
|
-
def repealed?
|
366
|
-
!!repealed_on
|
367
|
-
end
|
368
|
-
|
369
|
-
# The date on which this act was repealed, or nil if never repealed
|
370
|
-
#
|
371
|
-
# @return [String] date of repeal or nil
|
372
|
-
def repealed_on
|
373
|
-
repeal_el = repeal
|
374
|
-
repeal_el ? Time.parse(repeal_el['date']) : nil
|
375
|
-
end
|
376
|
-
|
377
|
-
# The element representing the reference that caused the repeal of this
|
378
|
-
# act, or nil.
|
379
|
-
#
|
380
|
-
# @return [Nokogiri::XML::Node] element of reference to repealing act, or nil
|
381
|
-
def repealed_by
|
382
|
-
repeal_el = repeal
|
383
|
-
return nil unless repeal_el
|
384
|
-
|
385
|
-
source_id = repeal_el['source'].sub(/^#/, '')
|
386
|
-
@meta.at_xpath("./a:references/a:passiveRef[@id='#{source_id}']", a: NS)
|
387
|
-
end
|
388
|
-
|
389
|
-
# The XML element representing the event of repeal of this act, or nil
|
390
|
-
#
|
391
|
-
# @return [Nokogiri::XML::Node]
|
392
|
-
def repeal
|
393
|
-
# <lifecycle source="#this">
|
394
|
-
# <eventRef id="e1" date="2010-07-28" source="#original" type="generation"/>
|
395
|
-
# <eventRef id="e2" date="2012-04-26" source="#amendment-1" type="amendment"/>
|
396
|
-
# <eventRef id="e3" date="2014-01-17" source="#repeal" type="repeal"/>
|
397
|
-
# </lifecycle>
|
398
|
-
@meta.at_xpath('./a:lifecycle/a:eventRef[@type="repeal"]', a: NS)
|
399
|
-
end
|
400
|
-
|
401
|
-
# The date at which this particular XML manifestation of this document was generated.
|
402
|
-
#
|
403
|
-
# @return [String] date, YYYY-MM-DD
|
404
|
-
def manifestation_date
|
405
|
-
node = @meta.at_xpath('./a:identification/a:FRBRManifestation/a:FRBRdate[@name="Generation"]', a: NS)
|
406
|
-
node && node['date']
|
407
|
-
end
|
408
|
-
|
409
|
-
# Validate the XML behind this document against the Akoma Ntoso schema and return
|
410
|
-
# any errors.
|
411
|
-
#
|
412
|
-
# @return [Object] array of errors, possibly empty
|
413
|
-
def validate
|
414
|
-
@schema ||= Dir.chdir(File.dirname(__FILE__) + "/schemas") { Nokogiri::XML::Schema(File.read('akomantoso20.xsd')) }
|
415
|
-
@schema.validate(@doc)
|
416
|
-
end
|
417
|
-
|
418
|
-
# Does this document validate against the schema?
|
419
|
-
#
|
420
|
-
# @see {#validate}
|
421
|
-
def validates?
|
422
|
-
validate.empty?
|
423
|
-
end
|
424
|
-
|
425
|
-
def inspect
|
426
|
-
"<#{self.class.name} @id_uri=\"#{@id_uri}\">"
|
427
|
-
end
|
428
|
-
|
429
|
-
protected
|
430
|
-
|
431
|
-
# Parse the FRBR Uri into its constituent parts
|
432
|
-
def extract_id_uri
|
433
|
-
@id_uri = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRuri', a: NS)['value']
|
434
|
-
empty, @country, @nature, date, @num = @id_uri.split('/')
|
435
|
-
|
436
|
-
# yyyy-mm-dd
|
437
|
-
@year = date.split('-', 2)[0]
|
438
|
-
end
|
439
|
-
|
440
|
-
def build_id_uri
|
441
|
-
# /za/act/2002/3
|
442
|
-
"/#{@country}/#{@nature}/#{@year}/#{@num}"
|
443
|
-
end
|
444
|
-
|
445
|
-
# This rebuild's the FRBR uri for this document using its constituent components. It will
|
446
|
-
# update the XML then re-split the URI and grab its components.
|
447
|
-
def rebuild_id_uri
|
448
|
-
self.id_uri = build_id_uri
|
449
|
-
end
|
450
|
-
end
|
451
|
-
|
452
|
-
end
|