iq_rdf 0.0.14
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.
- data/LICENSE +177 -0
- data/README.rdoc +77 -0
- data/Rakefile +32 -0
- data/iq_rdf.gemspec +37 -0
- data/lib/iq_rdf.rb +78 -0
- data/lib/iq_rdf/blank_node.rb +50 -0
- data/lib/iq_rdf/collection.rb +53 -0
- data/lib/iq_rdf/document.rb +93 -0
- data/lib/iq_rdf/literal.rb +59 -0
- data/lib/iq_rdf/namespace.rb +71 -0
- data/lib/iq_rdf/node.rb +57 -0
- data/lib/iq_rdf/plain_turtle_literal.rb +30 -0
- data/lib/iq_rdf/predicate.rb +43 -0
- data/lib/iq_rdf/predicate_namespace.rb +63 -0
- data/lib/iq_rdf/rails/iq_rdf.rb +42 -0
- data/lib/iq_rdf/uri.rb +69 -0
- data/lib/iq_rdf/version.rb +17 -0
- data/rails/init.rb +15 -0
- data/test/iq_rdf_test.rb +54 -0
- data/test/test_helper.rb +18 -0
- data/test/turtle_test.rb +215 -0
- data/test/xml_test.rb +203 -0
- metadata +120 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Collection
|
17
|
+
|
18
|
+
attr_reader :elements
|
19
|
+
|
20
|
+
def initialize(collection)
|
21
|
+
@elements = []
|
22
|
+
collection.each do |element|
|
23
|
+
element = Literal.new(element) unless element.is_a?(IqRdf::Uri)
|
24
|
+
@elements << element
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s(lang = nil)
|
29
|
+
"(#{@elements.map{|e| e.to_s(lang)}.join(" ")})"
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_xml(xml, elements = nil, &block)
|
33
|
+
elements ||= @elements.dup
|
34
|
+
block.call({},
|
35
|
+
lambda {
|
36
|
+
xml.rdf :List do
|
37
|
+
elements.shift.build_xml(xml) do |*args|
|
38
|
+
xml.rdf(:first, *args)
|
39
|
+
end
|
40
|
+
if elements.size > 0
|
41
|
+
build_xml(xml, elements) do |opts, block|
|
42
|
+
xml.rdf :rest, &block
|
43
|
+
end
|
44
|
+
else
|
45
|
+
xml.rdf :rest, "rdf:resource" => Rdf.nil.full_uri
|
46
|
+
end
|
47
|
+
end
|
48
|
+
}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Document
|
17
|
+
|
18
|
+
def initialize(default_namespace_uri_prefix = nil, *args)
|
19
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
20
|
+
raise ArgumentError, "If given, parameter :lang has to be a Symbol" unless options[:lang].nil? || options[:lang].is_a?(Symbol)
|
21
|
+
|
22
|
+
self.namespaces(:default => default_namespace_uri_prefix) if default_namespace_uri_prefix
|
23
|
+
self.namespaces(:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
24
|
+
|
25
|
+
@document_language = options[:lang]
|
26
|
+
|
27
|
+
@nodes = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def namespaces(namespaces)
|
31
|
+
raise ArgumentError, "Parameter 'namespaces' has to be a hash" unless namespaces.is_a?(Hash)
|
32
|
+
|
33
|
+
namespaces.each do |name, uri_prefix|
|
34
|
+
uri_prefix = ::URI.parse(uri_prefix)
|
35
|
+
raise ArgumentError, "Parameter 'namespaces' must be im the form {Symbol => URIString, ...}" unless name.is_a? Symbol
|
36
|
+
|
37
|
+
register_namespace(name, uri_prefix)
|
38
|
+
end
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def <<(node)
|
43
|
+
return if node.nil?
|
44
|
+
raise ArgumentError, "Node must be an IqRdf::Uri and a Subject!" unless node.is_a?(IqRdf::Uri) and node.is_subject?
|
45
|
+
@nodes << node
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_turtle
|
49
|
+
s = ""
|
50
|
+
@namespaces.values.each do |namespace|
|
51
|
+
s << "@prefix #{namespace.turtle_token}: <#{namespace.uri_prefix}>.\n"
|
52
|
+
end
|
53
|
+
s << "\n"
|
54
|
+
@nodes.each do |node|
|
55
|
+
pref = "#{node.to_s(@document_language)}"
|
56
|
+
if node.rdf_type
|
57
|
+
s << "#{pref} a #{node.rdf_type}"
|
58
|
+
pref = ";\n" + "".ljust(node.to_s(@document_language).length)
|
59
|
+
end
|
60
|
+
node.nodes.each do |predicate|
|
61
|
+
s << "#{pref} #{predicate.to_s} #{predicate.nodes.map{|o| o.to_s(predicate.lang || node.lang || @document_language)}.join(", ")}"
|
62
|
+
pref = ";\n" + "".ljust(node.to_s(@document_language).length)
|
63
|
+
end
|
64
|
+
s << ".\n"
|
65
|
+
end
|
66
|
+
s
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_xml
|
70
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
71
|
+
xml.instruct!
|
72
|
+
opts = {}
|
73
|
+
@namespaces.values.each{ |namespace|
|
74
|
+
opts[namespace.token == :default ? "xmlns" : "xmlns:#{namespace.token.to_s}"] = namespace.uri_prefix
|
75
|
+
}
|
76
|
+
opts["xml:lang"] = @document_language if @document_language
|
77
|
+
|
78
|
+
xml.rdf(:RDF, opts) do
|
79
|
+
@nodes.each do |node|
|
80
|
+
node.build_xml(xml)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
xml.target!
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def register_namespace(name, uri_prefix)
|
89
|
+
(@namespaces ||= {})[name] = IqRdf::Namespace.create(name, uri_prefix)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Literal
|
17
|
+
|
18
|
+
def initialize(obj, lang = nil)
|
19
|
+
@obj = obj
|
20
|
+
@lang = lang
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s(lang = nil)
|
24
|
+
lang = @lang || lang # Use the Literals lang when given
|
25
|
+
if @obj.is_a?(URI)
|
26
|
+
"<#{@obj.to_s}>"
|
27
|
+
elsif @obj === true
|
28
|
+
"true"
|
29
|
+
elsif @obj === false
|
30
|
+
"false"
|
31
|
+
elsif @obj.is_a?(Numeric)
|
32
|
+
@obj.to_s
|
33
|
+
else
|
34
|
+
quote = @obj.to_s.include?("\n") ? '"""' : '"'
|
35
|
+
"#{quote}#{@obj.to_s.gsub("\\", "\\\\\\\\").gsub(/"/, "\\\"")}#{quote}#{(lang && lang != :none) ? "@#{lang}" : ""}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_xml(xml, &block)
|
40
|
+
if @obj.is_a?(URI)
|
41
|
+
block.call("rdf:resource" => @obj.to_s)
|
42
|
+
else
|
43
|
+
opts = {}
|
44
|
+
{ Integer => "http://www.w3.org/2001/XMLSchema#integer",
|
45
|
+
Float => "http://www.w3.org/2001/XMLSchema#decimal",
|
46
|
+
TrueClass => "http://www.w3.org/2001/XMLSchema#boolean",
|
47
|
+
FalseClass => "http://www.w3.org/2001/XMLSchema#boolean",
|
48
|
+
}.each do |klass, s|
|
49
|
+
opts["rdf:datatype"] = s if @obj.is_a?(klass)
|
50
|
+
end
|
51
|
+
opts["xml:lang"] = @lang if @lang
|
52
|
+
block.call(@obj.to_s, opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :full_uri, :to_s
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Namespace
|
17
|
+
|
18
|
+
# Methods used in child classes
|
19
|
+
|
20
|
+
def self.token
|
21
|
+
self.instance_variable_get(:@token)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.uri_prefix
|
25
|
+
self.instance_variable_get(:@uri_prefix)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.turtle_token
|
29
|
+
self.token != :default ? self.token.to_s : ""
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.build_uri(postfix, type = nil, &block)
|
33
|
+
uri = IqRdf::Uri.new(self, postfix, type)
|
34
|
+
if block
|
35
|
+
yield(uri)
|
36
|
+
end
|
37
|
+
uri
|
38
|
+
end
|
39
|
+
|
40
|
+
# Namespace only methods
|
41
|
+
|
42
|
+
def self.create(token, uri_prefix)
|
43
|
+
klass_name = self.class_name(token)
|
44
|
+
klass = IqRdf.const_defined?(klass_name) ? IqRdf.const_get(klass_name) : IqRdf.const_set(klass_name, Class.new(self))
|
45
|
+
klass.instance_variable_set(:@token, token)
|
46
|
+
klass.instance_variable_set(:@uri_prefix, uri_prefix)
|
47
|
+
klass
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find_namespace_class(token)
|
51
|
+
klass_name = self.class_name(token)
|
52
|
+
IqRdf.const_get(klass_name) if IqRdf.const_defined?(klass_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.dummy_empty_namespace
|
56
|
+
@dummy_empty_namespace ||= Class.new(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def self.method_missing(method_name, *args, &block)
|
62
|
+
type = args.shift if args[0].is_a?(IqRdf::Uri)
|
63
|
+
self.build_uri(method_name, type, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.class_name(name)
|
67
|
+
name.to_s.gsub(/(^|_)(.)/) { $2.upcase }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/iq_rdf/node.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Node
|
17
|
+
attr_reader :nodes
|
18
|
+
attr_reader :lang
|
19
|
+
|
20
|
+
def initialize(lang = nil)
|
21
|
+
@nodes = []
|
22
|
+
@lang = lang
|
23
|
+
end
|
24
|
+
|
25
|
+
# You can add Nodes (Uris, Blank Nodes, Predicates), Literals and Collections
|
26
|
+
# So a Node has the following structure:
|
27
|
+
# <node> <uri> or <node> <literal> (tuple)
|
28
|
+
# <node> <predicate> == <node> (<predicate_node> <predicate.nodes>) (triples)
|
29
|
+
def <<(node)
|
30
|
+
raise ArgumentError, "#{node.inspect} is no IqRdf::Node or a IqRdf::Literal or a IqRdf::Collection" unless node.is_a?(IqRdf::Node) || node.is_a?(IqRdf::Literal) || node.is_a?(IqRdf::Collection)
|
31
|
+
@nodes << node
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method_name, *args, &block)
|
35
|
+
if (namespace_class = Namespace.find_namespace_class(method_name))
|
36
|
+
return IqRdf::PredicateNamespace.new(self, namespace_class) # some_node.>namespace<...
|
37
|
+
else
|
38
|
+
return IqRdf::PredicateNamespace.new(self, IqRdf::Default).build_predicate(method_name, *args, &block) # some_node.>predicate<()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_subject?()
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_full_uri_predicate(uri, *args, &block)
|
47
|
+
raise ArgumentError, "uri musst be an ::URI" unless uri.is_a?(::URI)
|
48
|
+
|
49
|
+
IqRdf::PredicateNamespace.new(self, Namespace.dummy_empty_namespace).build_predicate(uri, *args, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def xml_lang
|
53
|
+
@lang && (@lang == :none ? "" : @lang)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
# This is a dummy class for some needs where
|
17
|
+
class PlainTurtleLiteral < Literal
|
18
|
+
|
19
|
+
def initialize(obj)
|
20
|
+
@obj = obj
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s(lang = nil)
|
24
|
+
@obj.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :full_uri, :to_s
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class Predicate < Uri
|
17
|
+
|
18
|
+
attr_reader :subject
|
19
|
+
|
20
|
+
def initialize(namespace, uri_postfix, subject, lang = nil)
|
21
|
+
super(namespace, uri_postfix, nil, lang)
|
22
|
+
@subject = subject
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_xml(xml)
|
26
|
+
raise "XML Output won't work with full URIs as predicates yet" unless namespace.token # There is a dummy_empty_namespace without token => postfix is a full uri!
|
27
|
+
nodes.each do |node|
|
28
|
+
node.build_xml(xml) do |*args|
|
29
|
+
block = args.pop if args.last.is_a?(Proc)
|
30
|
+
params = namespace.token == :default ? [self.uri_postfix.to_s] : [namespace.token.to_s, self.uri_postfix.to_sym]
|
31
|
+
params += args
|
32
|
+
params << {"xml:lang" => xml_lang} if xml_lang
|
33
|
+
if block
|
34
|
+
xml.tag!(*params, &block)
|
35
|
+
else
|
36
|
+
xml.tag!(*params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Copyright 2011 Till Schulte-Coerne (innoQ Deutschland GmbH)
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module IqRdf
|
16
|
+
class PredicateNamespace
|
17
|
+
|
18
|
+
def initialize(subject, namespace)
|
19
|
+
@subject = subject
|
20
|
+
@predicate_namespace = namespace
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_predicate(postfix, *args, &block)
|
24
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
25
|
+
objects = args
|
26
|
+
predicate = IqRdf::Predicate.new(@predicate_namespace, postfix, @subject, options[:lang])
|
27
|
+
if (block)
|
28
|
+
raise ArgumentError, "A predicate may either have agruments or a block, ot both." if objects.size > 0
|
29
|
+
blank_node = IqRdf::BlankNode.new
|
30
|
+
yield blank_node
|
31
|
+
predicate << blank_node
|
32
|
+
else
|
33
|
+
return nil if options[:suppress_if_empty] === true && objects.size == 0
|
34
|
+
raise ArgumentError, "At least one object is required in predicate call" if objects.size == 0
|
35
|
+
objects.each do |o|
|
36
|
+
if o.is_a?(Array)
|
37
|
+
return nil if options[:suppress_if_empty] === true && o.size == 0
|
38
|
+
o = IqRdf::Collection.new(o)
|
39
|
+
elsif o.is_a?(IqRdf::Node)
|
40
|
+
raise ArgumentError, "Objects may not have nested triples in this Implementation of RDF" if o.is_subject?
|
41
|
+
elsif o.is_a?(Literal)
|
42
|
+
# We're already done
|
43
|
+
elsif o.is_a?(Symbol)
|
44
|
+
o = IqRdf::Default.build_uri(o)
|
45
|
+
else
|
46
|
+
return nil if options[:suppress_if_empty] === true && (o.nil? || o === "")
|
47
|
+
o = Literal.new(o)
|
48
|
+
end
|
49
|
+
predicate << o
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@subject << predicate
|
53
|
+
@subject
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def method_missing(method_name, *args)
|
59
|
+
build_predicate(method_name, *args)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|