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.
@@ -1,62 +0,0 @@
1
- require 'slaw/act'
2
-
3
- module Slaw
4
- # An extension of {Slaw::Act} which wraps an AkomaNtoso XML document describing an By-Law.
5
- #
6
- # There are minor differences between Acts and By-laws, the most notable being that a by-law
7
- # is not identified by a year and a number, and therefore has a different FRBR uri structure.
8
- class ByLaw < Act
9
-
10
- # [String] The code of the region this by-law applies to
11
- attr_reader :region
12
-
13
- # [String] A short file-like name of this by-law, unique within its year and region
14
- attr_reader :name
15
-
16
- # ByLaws don't have numbers, use their short-name instead
17
- def num
18
- name
19
- end
20
-
21
- def title
22
- node = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: NS)
23
- title = node ? node['value'] : "(Unknown)"
24
-
25
- if amended? and not title.end_with?("as amended")
26
- title = title + " as amended"
27
- end
28
-
29
- title
30
- end
31
-
32
- # Set the short (file-like) name for this bylaw. This changes the {#id_uri}.
33
- def name=(value)
34
- @name = value
35
- rebuild_id_uri
36
- end
37
-
38
- # Set the region code for this bylaw. This changes the {#id_uri}.
39
- def region=(value)
40
- @region = value
41
- rebuild_id_uri
42
- end
43
-
44
- protected
45
-
46
- def extract_id_uri
47
- # /za/by-law/cape-town/2010/public-parks
48
-
49
- @id_uri = @meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRuri', a: NS)['value']
50
- empty, @country, @nature, @region, date, @name = @id_uri.split('/')
51
-
52
- # yyyy[-mm-dd]
53
- @year = date.split('-', 2)[0]
54
- end
55
-
56
- def build_id_uri
57
- # /za/by-law/cape-town/2010/public-parks
58
- "/#{@country}/#{@nature}/#{@region}/#{@year}/#{@name}"
59
- end
60
-
61
- end
62
- end
@@ -1,60 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Slaw
4
- # A collection of Act instances.
5
- #
6
- # This is useful for looking up acts by their FRBR uri and for
7
- # loading a collection of XML act documents.
8
- #
9
- # This collection is enumerable and can be iterated over. Use {#items} to
10
- # access the underlying array of objects.
11
- #
12
- # @example Load a collection of acts and then iterate over them.
13
- #
14
- # acts = Slaw::DocumentCollection.new
15
- # acts.discover('/path/to/acts/')
16
- #
17
- # for act in acts
18
- # puts act.short_name
19
- # end
20
- #
21
- class DocumentCollection
22
-
23
- include Enumerable
24
- extend Forwardable
25
-
26
- # [Array<Act>] The underlying array of acts
27
- attr_accessor :items
28
-
29
- def_delegators :items, :each, :<<, :length
30
-
31
- def initialize(items=nil)
32
- @items = items || []
33
- end
34
-
35
- # Find all XML files in `path` and add them into this
36
- # collection.
37
- #
38
- # @param path [String] the path to glob for xml files
39
- # @param cls [Class] the class to instantiate for each file
40
- #
41
- # @return [DocumentCollection] this collection
42
- def discover(path, cls=Slaw::Act)
43
- for fname in Dir.glob("#{path}/**/*.xml")
44
- @items << cls.new(fname)
45
- end
46
-
47
- self
48
- end
49
-
50
- # Try to find an act who's FRBRuri matches this one,
51
- # returning nil on failure
52
- #
53
- # @param uri [String] the uri to look for
54
- #
55
- # @return [Act, nil] the act, or nil
56
- def for_uri(uri)
57
- return @items.find { |doc| doc.id_uri == uri }
58
- end
59
- end
60
- end
@@ -1,23 +0,0 @@
1
- module Slaw
2
- # An event in the lifecycle of an act
3
- class LifecycleEvent
4
- include Slaw::Namespace
5
-
6
- # Date of the event
7
- attr_accessor :date
8
-
9
- # type of the event
10
- attr_accessor :type
11
-
12
- # the source of the event, an XML reference element
13
- attr_accessor :source
14
-
15
- def initialize(element)
16
- @date = element['date']
17
- @type = element['type']
18
-
19
- source_id = element['source'][1..-1]
20
- @source = element.document.at_xpath("//a:references/*[@id=\"#{source_id}\"]", a: NS)
21
- end
22
- end
23
- end
@@ -1,70 +0,0 @@
1
- module Slaw
2
- module Render
3
-
4
- # Support for transforming XML AN documents into HTML.
5
- #
6
- # This rendering is done using XSLT stylesheets. Both an entire
7
- # document and fragments can be rendered.
8
- class HTMLRenderer
9
-
10
- # [Hash] A Hash of Nokogiri::XSLT objects
11
- attr_accessor :xslt
12
-
13
- def initialize
14
- here = File.dirname(__FILE__)
15
-
16
- @xslt = {
17
- act: Nokogiri::XSLT(File.open(File.join([here, 'xsl/act.xsl']))),
18
- fragment: Nokogiri::XSLT(File.open(File.join([here, 'xsl/fragment.xsl']))),
19
- }
20
- end
21
-
22
- # Transform an entire XML document (a Nokogiri::XML::Document object) into HTML.
23
- # Specify `base_url` to manage the base for relative URLs generated by
24
- # the transform.
25
- #
26
- # @param doc [Nokogiri::XML::Document] document to render
27
- # @param base_url [String] root URL for relative URLs (cannot be empty)
28
- #
29
- # @return [String]
30
- def render(doc, base_url='')
31
- params = _transform_params({'base_url' => base_url})
32
- _run_xslt(:act, doc, params)
33
- end
34
-
35
- # Transform just a single node and its children into HTML.
36
- #
37
- # If +elem+ has an id, we use xpath to tell the XSLT which
38
- # element to transform. Otherwise we copy the node into a new
39
- # tree and apply the XSLT to that.
40
- #
41
- # @param node [Nokogiri::XML::Node] node to render
42
- # @param base_url [String] root URL for relative URLs (cannot be empty)
43
- #
44
- # @return [String]
45
- def render_node(node, base_url='')
46
- params = _transform_params({'base_url' => base_url})
47
-
48
- if node.id
49
- params += ['root_elem', "//*[@id='#{node.id}']"]
50
- doc = node.document
51
- else
52
- # create a new document with just this element at the root
53
- doc = Nokogiri::XML::Document.new
54
- doc.root = node
55
- params += ['root_elem', '*']
56
- end
57
-
58
- _run_xslt(:fragment, doc, params)
59
- end
60
-
61
- def _run_xslt(xslt, doc, params)
62
- @xslt[xslt].transform(doc, params).to_s
63
- end
64
-
65
- def _transform_params(params)
66
- Nokogiri::XSLT.quote_params(params)
67
- end
68
- end
69
- end
70
- end
@@ -1,15 +0,0 @@
1
- <?xml version="1.0"?>
2
- <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
3
- xmlns:a="http://www.akomantoso.org/2.0"
4
- exclude-result-prefixes="a">
5
-
6
- <xsl:import href="elements.xsl" />
7
-
8
- <xsl:output method="html" />
9
-
10
- <xsl:template match="/">
11
- <xsl:apply-templates select="a:akomaNtoso/a:act" />
12
- </xsl:template>
13
-
14
- </xsl:stylesheet>
15
-
@@ -1,120 +0,0 @@
1
- <?xml version="1.0"?>
2
- <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
3
- xmlns:a="http://www.akomantoso.org/2.0"
4
- exclude-result-prefixes="a">
5
-
6
- <xsl:template match="a:act">
7
- <xsl:element name="span" namespace="">
8
- <xsl:attribute name="class">an-act</xsl:attribute>
9
- <xsl:apply-templates select="a:preamble" />
10
- <xsl:apply-templates select="a:body/a:part | a:body/a:chapter | a:body/a:section" />
11
- </xsl:element>
12
- </xsl:template>
13
-
14
- <!-- for parts and chapters, include an easily stylable heading -->
15
- <xsl:template match="a:part">
16
- <div class="an-part" id="{@id}">
17
- <h1>
18
- <xsl:text>Part </xsl:text>
19
- <xsl:value-of select="./a:num" />
20
- <xsl:text> - </xsl:text>
21
- <xsl:value-of select="./a:heading" />
22
- </h1>
23
-
24
- <xsl:apply-templates select="./*[not(self::a:num) and not(self::a:heading)]" />
25
- </div>
26
- </xsl:template>
27
-
28
- <xsl:template match="a:chapter">
29
- <div class="an-chapter" id="{@id}">
30
- <h1>
31
- <xsl:text>Chapter </xsl:text>
32
- <xsl:value-of select="./a:num" />
33
- <br/>
34
- <xsl:value-of select="./a:heading" />
35
- </h1>
36
-
37
- <xsl:apply-templates select="./*[not(self::a:num) and not(self::a:heading)]" />
38
- </div>
39
- </xsl:template>
40
-
41
- <!-- the schedules "chapter" isn't actually a chapter -->
42
- <xsl:template match="a:chapter[starts-with(@id, 'schedule')]">
43
- <div class="an-chapter" id="{@id}">
44
- <h1>
45
- <xsl:text>Schedule </xsl:text>
46
- <xsl:value-of select="./a:num" />
47
- <br/>
48
- <xsl:value-of select="./a:heading" />
49
- </h1>
50
-
51
- <xsl:apply-templates select="./*[not(self::a:num) and not(self::a:heading)]" />
52
- </div>
53
- </xsl:template>
54
-
55
- <xsl:template match="a:section">
56
- <div class="an-{local-name()}" id="{@id}">
57
- <h3>
58
- <xsl:value-of select="./a:num" />
59
- <xsl:text> </xsl:text>
60
- <xsl:value-of select="./a:heading" />
61
- </h3>
62
-
63
- <xsl:apply-templates select="./*[not(self::a:num) and not(self::a:heading)]" />
64
- </div>
65
- </xsl:template>
66
-
67
- <xsl:template match="a:subsection">
68
- <span class="an-{local-name()}" id="{@id}">
69
- <xsl:apply-templates select="./*[not(self::a:heading)]" />
70
- </span>
71
- </xsl:template>
72
-
73
- <!-- for term nodes, ensure we keep the refersTo element -->
74
- <xsl:template match="a:term">
75
- <a class="an-{local-name()}">
76
- <xsl:attribute name="data-refers-to">
77
- <xsl:value-of select="@refersTo" />
78
- </xsl:attribute>
79
-
80
- <xsl:attribute name="href"><xsl:value-of select="$base_url" />/definitions/#def-<xsl:value-of select="translate(@refersTo, '#', '')" /></xsl:attribute>
81
-
82
- <xsl:apply-templates />
83
- </a>
84
- </xsl:template>
85
-
86
- <!-- for all nodes, generate a SPAN element with a class matching
87
- the AN name of the node and copy over the ID if it exists -->
88
- <xsl:template match="*">
89
- <span class="an-{local-name()}">
90
- <xsl:if test="@id">
91
- <xsl:attribute name="id">
92
- <xsl:value-of select="@id" />
93
- </xsl:attribute>
94
- </xsl:if>
95
- <xsl:apply-templates />
96
- </span>
97
- </xsl:template>
98
-
99
- <!-- For HTML table elements, copy them over then apply normal AN
100
- processing to their contents -->
101
- <xsl:template match="a:table | a:tr | a:th | a:td">
102
- <xsl:element name="{local-name()}">
103
- <xsl:copy-of select="@*" />
104
- <xsl:apply-templates />
105
- </xsl:element>
106
- </xsl:template>
107
-
108
- <!-- special HTML elements -->
109
- <xsl:template match="a:a | a:abbr | a:b | a:i | a:span | a:sub | a:sup | a:u">
110
- <xsl:element name="{local-name()}">
111
- <xsl:copy-of select="@*" />
112
- <xsl:apply-templates />
113
- </xsl:element>
114
- </xsl:template>
115
-
116
- <xsl:template match="a:eol">
117
- <xsl:element name="br" />
118
- </xsl:template>
119
-
120
- </xsl:stylesheet>
@@ -1,16 +0,0 @@
1
- <?xml version="1.0"?>
2
- <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
3
- xmlns:a="http://www.akomantoso.org/2.0"
4
- exclude-result-prefixes="a">
5
-
6
- <xsl:import href="elements.xsl" />
7
-
8
- <xsl:output method="html" />
9
-
10
- <xsl:template match="/">
11
- <!-- root_elem is passed in as an xpath parameter -->
12
- <xsl:apply-templates select="$root_elem" />
13
- </xsl:template>
14
-
15
- </xsl:stylesheet>
16
-
@@ -1,56 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
- require 'slaw'
5
-
6
- describe Slaw::Act do
7
- let(:filename) { File.dirname(__FILE__) + "/fixtures/community-fire-safety.xml" }
8
- subject { Slaw::Act.new(filename) }
9
-
10
- it 'should have correct basic properties' do
11
- subject.title.should == 'Community Fire Safety By-law'
12
- subject.amended?.should be_true
13
- end
14
-
15
- it 'should set the title correctly' do
16
- subject.title = 'foo'
17
- subject.meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: Slaw::NS)['value'].should == 'foo'
18
- end
19
-
20
- it 'should set the title if it doesnt exist' do
21
- subject.meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: Slaw::NS).remove
22
- subject.title = 'bar'
23
- subject.title.should == 'bar'
24
- end
25
-
26
- it 'should set the publication details' do
27
- subject.meta.at_xpath('./a:publication', a: Slaw::NS).remove
28
-
29
- subject.published!(name: 'foo', number: '1234', date: '2014-01-01')
30
- subject.publication['name'].should == 'foo'
31
- subject.publication['showAs'].should == 'foo'
32
- subject.publication['number'].should == '1234'
33
- end
34
-
35
- it 'should get/set the work date' do
36
- subject.date.should == '2002-02-28'
37
-
38
- subject.date = '2014-01-01'
39
- subject.date.should == '2014-01-01'
40
- subject.meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRdate[@name="Generation"]', a: Slaw::NS)['date'].should == '2014-01-01'
41
- subject.meta.at_xpath('./a:identification/a:FRBRExpression/a:FRBRdate[@name="Generation"]', a: Slaw::NS)['date'].should == '2014-01-01'
42
-
43
- subject.id_uri.should == '/za/by-law/2014/2002'
44
- end
45
-
46
- it 'should update the uri when the year changes' do
47
- subject.id_uri.should == '/za/by-law/cape-town/2002/community-fire-safety'
48
- subject.year = '1980'
49
- subject.id_uri.should == '/za/by-law/1980/2002'
50
- end
51
-
52
- it 'should validate' do
53
- subject.validate.should == []
54
- subject.validates?.should be_true
55
- end
56
- end
@@ -1,49 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
- require 'slaw'
5
-
6
- describe Slaw::ByLaw do
7
- let(:filename) { File.dirname(__FILE__) + "/fixtures/community-fire-safety.xml" }
8
- subject { Slaw::ByLaw.new(filename) }
9
-
10
- it 'should have correct basic properties' do
11
- subject.title.should == 'Community Fire Safety By-law as amended'
12
- subject.amended?.should be_true
13
- end
14
-
15
- it 'should update the uri when the region changes' do
16
- subject.id_uri.should == '/za/by-law/cape-town/2002/community-fire-safety'
17
- subject.region = 'foo-bar'
18
- subject.id_uri.should == '/za/by-law/foo-bar/2002/community-fire-safety'
19
- end
20
-
21
- it 'should update the uri when the name changes' do
22
- subject.id_uri.should == '/za/by-law/cape-town/2002/community-fire-safety'
23
- subject.name = 'foo-bar'
24
- subject.id_uri.should == '/za/by-law/cape-town/2002/foo-bar'
25
- end
26
-
27
- it 'should set the title if it doesnt exist' do
28
- subject.meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRalias', a: Slaw::NS).remove
29
- subject.title = 'bar'
30
- subject.title.should == 'bar as amended'
31
- end
32
-
33
- it 'should get/set the work date' do
34
- subject.date.should == '2002-02-28'
35
-
36
- subject.date = '2014-01-01'
37
- subject.date.should == '2014-01-01'
38
- subject.meta.at_xpath('./a:identification/a:FRBRWork/a:FRBRdate[@name="Generation"]', a: Slaw::NS)['date'].should == '2014-01-01'
39
- subject.meta.at_xpath('./a:identification/a:FRBRExpression/a:FRBRdate[@name="Generation"]', a: Slaw::NS)['date'].should == '2014-01-01'
40
-
41
- subject.id_uri.should == '/za/by-law/cape-town/2014/community-fire-safety'
42
- end
43
-
44
- it 'should update the uri when the year changes' do
45
- subject.id_uri.should == '/za/by-law/cape-town/2002/community-fire-safety'
46
- subject.year = '1980'
47
- subject.id_uri.should == '/za/by-law/cape-town/1980/community-fire-safety'
48
- end
49
- end