nokogiri_schematron_builder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 24f02a10a7493555198daad2202e63376d1e7bbc9af7b91c79318d4c36239c41
4
+ data.tar.gz: 9bf5e2b1ac5e0e6a7949bcef45331e8277a823a13cecb5b8c387ccdadee41c34
5
+ SHA512:
6
+ metadata.gz: babe38706760546dfbb24513d9a9453c4156769837279c75967a253e8fd5bea48fb101c014c25299973e960d59d280dc5de5413a2ce63aac80de9a64320a4928
7
+ data.tar.gz: 175f4df54fa99d350c8823519c3d22c68be65c5912f98bf4605b949580bbd803590ffe703a6aa662d4a47509aff00a0439b65ca5b455e9f8c05e94b908b0bce7
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in nokogiri_schematron_builder.gemspec
6
+ gemspec
@@ -0,0 +1,32 @@
1
+ nokogiri_schematron_builder
2
+
3
+ Copyright (c) 2019, Battelle Memorial Institute
4
+ All rights reserved.
5
+
6
+ 1. Battelle Memorial Institute (hereinafter Battelle) hereby grants permission
7
+ to any person or entity lawfully obtaining a copy of this software and
8
+ associated documentation files (hereinafter "the Software") to redistribute
9
+ and use the Software in source and binary forms, with or without
10
+ modification. Such person or entity may use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and may permit
12
+ others to do so, subject to the following conditions:
13
+
14
+ * Redistributions of source code must retain the above copyright notice, this
15
+ list of conditions and the following disclaimers.
16
+ * Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+ * Other than as used herein, neither the name Battelle Memorial Institute or
20
+ Battelle may be used in any form whatsoever without the express written
21
+ consent of Battelle.
22
+
23
+ 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ DISCLAIMED. IN NO EVENT SHALL BATTELLE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,109 @@
1
+ # nokogiri_schematron_builder
2
+
3
+ Build [Schematron](http://schematron.com) XML documents using [Nokogiri](https://nokogiri.org).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "nokogiri_schematron_builder"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install nokogiri_schematron_builder
20
+
21
+ ## Usage
22
+
23
+ Add this line to your application:
24
+
25
+ ```ruby
26
+ require "nokogiri/xml/schematron/schema"
27
+ ```
28
+
29
+ Create the schema using the domain-specific language:
30
+
31
+ ```ruby
32
+ schema = Nokogiri::XML::Schematron::Schema.new(title: "Example schema") do
33
+ ns(prefix: "ex", uri: "http://example.com/ns#")
34
+ pattern(name: "Example pattern") do
35
+ rule(context: "/") do
36
+ assert(test: "count(ex:A) >= 1", message: "element \"ex:A\" is REQUIRED")
37
+ end
38
+ rule(context: "/ex:A") do
39
+ assert(test: "count(ex:B) >= 0", message: "element \"ex:B\" is OPTIONAL")
40
+ end
41
+ rule(context: "/ex:A/ex:B") do
42
+ assert(test: "not(ex:C)", message: "element \"ex:C\" is NOT RECOMMENDED")
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ Or, equivalently:
49
+
50
+ ```ruby
51
+ schema = Nokogiri::XML::Schematron::Schema.new(title: "Example schema") do
52
+ ns(prefix: "ex", uri: "http://example.com/ns#")
53
+ pattern(name: "Example pattern") do
54
+ context("/") do
55
+ require("ex:A") do
56
+ permit("ex:B") do
57
+ reject("ex:C")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ ```
64
+
65
+ Next, construct a [`Nokogiri::XML::Builder`](https://nokogiri.org/rdoc/Nokogiri/XML/Builder.html) object:
66
+
67
+ ```ruby
68
+ builder = schema.to_builder(encoding: "UTF-8")
69
+ ```
70
+
71
+ Finally, generate the XML:
72
+
73
+ ```ruby
74
+ xml = builder.to_xml
75
+ ```
76
+
77
+ The result is:
78
+
79
+ ```xml
80
+ <?xml version="1.0" encoding="UTF-8"?>
81
+ <sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" title="Example schema">
82
+ <sch:ns prefix="ex" uri="http://example.com/ns#"/>
83
+ <sch:pattern name="Example pattern">
84
+ <sch:rule context="/">
85
+ <sch:assert test="count(ex:A) &gt;= 1">element "ex:A" is REQUIRED</sch:assert>
86
+ </sch:rule>
87
+ <sch:rule context="/ex:A">
88
+ <sch:assert test="count(ex:B) &gt;= 0">element "ex:B" is OPTIONAL</sch:assert>
89
+ </sch:rule>
90
+ <sch:rule context="/ex:A/ex:B">
91
+ <sch:assert test="not(ex:C)">element "ex:C" is NOT RECOMMENDED</sch:assert>
92
+ </sch:rule>
93
+ </sch:pattern>
94
+ </sch:schema>
95
+ ```
96
+
97
+ ## Development
98
+
99
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
100
+
101
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
102
+
103
+ ## License
104
+
105
+ [The 2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause)
106
+
107
+ ## Contributing
108
+
109
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pnnl/nokogiri_schematron_builder.
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ This material was prepared as an account of work sponsored by an agency of the
2
+ United States Government. Neither the United States Government nor the United
3
+ States Department of Energy, nor Battelle, nor any of their employees, nor any
4
+ jurisdiction or organization that has cooperated in the development of these
5
+ materials, makes any warranty, express or implied, or assumes any legal
6
+ liability or responsibility for the accuracy, completeness, or usefulness or any
7
+ information, apparatus, product, software, or process disclosed, or represents
8
+ that its use would not infringe privately owned rights.
9
+
10
+ Reference herein to any specific commercial product, process, or service by
11
+ trade name, trademark, manufacturer, or otherwise does not necessarily
12
+ constitute or imply its endorsement, recommendation, or favoring by the United
13
+ States Government or any agency thereof, or Battelle Memorial Institute. The
14
+ views and opinions of authors expressed herein do not necessarily state or
15
+ reflect those of the United States Government or any agency thereof.
16
+
17
+ PACIFIC NORTHWEST NATIONAL LABORATORY
18
+ operated by
19
+ BATTELLE
20
+ for the
21
+ UNITED STATES DEPARTMENT OF ENERGY
22
+ under Contract DE-AC05-76RL01830
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nokogiri/xml/schematron"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,8 @@
1
+ require "nokogiri/xml/schematron/version"
2
+
3
+ module Nokogiri
4
+ module XML
5
+ module Schematron
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,46 @@
1
+ require "nokogiri/xml/schematron/base"
2
+
3
+ module Nokogiri
4
+ module XML
5
+ module Schematron
6
+ # The internal representation of the +<sch:assert>+ XML element.
7
+ #
8
+ # For example:
9
+ #
10
+ # assertion = Nokogiri::XML::Schematron::Assertion.new(nil, test: "not(ex:Example)", message: "element \"ex:Example\" is NOT RECOMMENDED")
11
+ # # => #<Nokogiri::XML::Schematron::Assertion:0x00007fa739a55dd8 @parent=nil, @children=[], @options={:test=>"not(ex:Example)", :message=>"element \"ex:Example\" is NOT RECOMMENDED"}>
12
+ # assertion.to_builder.to_xml
13
+ # # => "<?xml version=\"1.0\"?>\n<sch:assert xmlns:sch=\"http://purl.oclc.org/dsdl/schematron\" test=\"not(ex:Example)\">element \"ex:Example\" is NOT RECOMMENDED</sch:assert>\n"
14
+ #
15
+ class Assertion < Nokogiri::XML::Schematron::Base
16
+ # @!attribute [rw] message
17
+ # @return [String] the text content of the +<sch:assert>+ XML element.
18
+ attribute :message
19
+
20
+ # @!attribute [rw] test
21
+ # @return [String] the value of the +@test+ XML attribute.
22
+ attribute :test
23
+
24
+ protected
25
+
26
+ def build!(xml)
27
+ xml["sch"].send(:assert, %w(test).inject(xmlns) { |acc, method_name|
28
+ unless (s = send(method_name.to_sym)).nil?
29
+ acc[method_name.to_s] = s
30
+ end
31
+
32
+ acc
33
+ }) do
34
+ unless (s = send(:message)).nil?
35
+ xml.text(s)
36
+ end
37
+
38
+ super(xml)
39
+ end
40
+
41
+ return
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,143 @@
1
+ require "nokogiri"
2
+
3
+ module Nokogiri
4
+ module XML
5
+ module Schematron
6
+ # The base class for internal representations of Schematron types.
7
+ # @abstract
8
+ class Base
9
+ class << self
10
+ # Defines methods for a named XML attribute.
11
+ #
12
+ # For example:
13
+ #
14
+ # attribute :name
15
+ #
16
+ # defines reader and writer methods that are equivalent to:
17
+ #
18
+ # def name
19
+ # @options[:name]
20
+ # end
21
+ #
22
+ # def name=(value)
23
+ # @options[:name] = value
24
+ # end
25
+ #
26
+ # @param name [#to_sym] the method name.
27
+ # @param options [Hash<Symbol, Object>] the options.
28
+ # @option options [Boolean] :reader (true) define the reader method?
29
+ # @option options [Boolean] :writer (true) define the writer method?
30
+ # @return [void]
31
+ def attribute(name, **options)
32
+ unless options[:reader] == false
33
+ define_method(name.to_sym) do
34
+ instance_variable_get(:@options).send(:[], name.to_sym)
35
+ end
36
+ end
37
+
38
+ unless options[:writer] == false
39
+ define_method(:"#{name.to_sym}=") do |value|
40
+ instance_variable_get(:@options).send(:[]=, name.to_sym, value)
41
+ end
42
+ end
43
+
44
+ return
45
+ end
46
+
47
+ # Defines methods for a named XML element.
48
+ #
49
+ # For example:
50
+ #
51
+ # element :name, DescendentOfBase
52
+ #
53
+ # where
54
+ #
55
+ # class DescendentOfBase < Base; end
56
+ #
57
+ # is a descendent of this class, defines methods that are equivalent to:
58
+ #
59
+ # def name(*args, &block)
60
+ # base = DescendentOfBase.new(self, *args, &block)
61
+ # @children << base
62
+ # base
63
+ # end
64
+ #
65
+ # @param name [#to_sym] the method name.
66
+ # @param klass [Class] the class.
67
+ # @return [void]
68
+ def element(name, klass)
69
+ define_method(name.to_sym) do |*args, &block|
70
+ base = klass.send(:new, self, *args, &block)
71
+ instance_variable_get(:@children) << base
72
+ base
73
+ end
74
+ end
75
+ end
76
+
77
+ # @return [Nokogiri::XML::Schematron::Base] the parent object.
78
+ attr_reader :parent
79
+
80
+ # @return [Array<Nokogiri::XML::Schematron::Base>] the children of the internal representation of the Schematron type.
81
+ attr_reader :children
82
+
83
+ # @return [Hash<Symbol, Object>] the options.
84
+ attr_reader :options
85
+
86
+ # Create a new +Base+ object.
87
+ #
88
+ # @param parent [Nokogiri::XML::Schematron::Base] the parent object.
89
+ # @param options [Hash<Symbol, Object>] the options.
90
+ # @yieldparam base [Nokogiri::XML::Schematron::Base] the internal representation of the Schematron type.
91
+ # @yieldreturn [void]
92
+ def initialize(parent, **options, &block)
93
+ @parent = parent
94
+ @children = []
95
+
96
+ @options = options
97
+
98
+ if block_given?
99
+ case block.arity
100
+ when 1 then block.call(self)
101
+ else instance_eval(&block)
102
+ end
103
+ end
104
+ end
105
+
106
+ # Convert this +Base+ object to a +Builder+ object.
107
+ #
108
+ # @return [Nokogiri::XML::Builder]
109
+ # @see https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Builder#initialize-instance_method
110
+ def to_builder(*args)
111
+ ::Nokogiri::XML::Builder.new(*args) do |xml|
112
+ build!(xml)
113
+ end
114
+ end
115
+
116
+ protected
117
+
118
+ # Build the XML representation of the Schematron type.
119
+ #
120
+ # @param xml [Nokogiri::XML::Builder] the XML builder.
121
+ # @return [void]
122
+ def build!(xml)
123
+ @children.each do |base|
124
+ base.send(:build!, xml)
125
+ end
126
+
127
+ return
128
+ end
129
+
130
+ # @return [Hash<String, String>] the hash of XML namespaces (URI by prefix).
131
+ def xmlns
132
+ if @parent.nil?
133
+ {
134
+ "xmlns:sch" => "http://purl.oclc.org/dsdl/schematron",
135
+ }
136
+ else
137
+ {}
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,33 @@
1
+ module Nokogiri
2
+ module XML
3
+ module Schematron
4
+ module Internal
5
+ module CoreExt
6
+ module Array
7
+ # Converts the array to a comma-separated sentence where the last
8
+ # element is joined by the connector word.
9
+ #
10
+ # @param array [Array<String>] the array of strings.
11
+ # @param options [Hash<Symbol, Object>] the options.
12
+ # @option options [String] :words_connector the sign or word used to join the elements in arrays with two or more elements.
13
+ # @option options [String] :two_words_connector the sign or word used to join the elements in arrays with two elements.
14
+ # @option options [String] :last_word_connector the sign or word used to join the last element in arrays with three or more elements.
15
+ # @return [String] the comma-separated sentence.
16
+ def self.to_sentence(array, options = {})
17
+ case array.length
18
+ when 0
19
+ ''
20
+ when 1
21
+ array[0].to_s.dup
22
+ when 2
23
+ "#{array[0]}#{options[:two_words_connector]}#{array[1]}"
24
+ else
25
+ "#{array[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{array[-1]}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end