tommorris-rena 0.0.1 → 0.0.2

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,89 +1,207 @@
1
- class Literal
2
- attr_accessor :contents, :lang
3
- def initialize(contents, lang = nil)
4
- @contents = contents
5
- if lang != nil && lang != false
6
- @lang = lang.downcase
1
+ module Rena
2
+ class Literal
3
+ class Encoding
4
+ def self.integer
5
+ @integer ||= coerce "http://www.w3.org/2001/XMLSchema#int"
6
+ end
7
+
8
+ def self.float
9
+ @float ||= coerce "http://www.w3.org/2001/XMLSchema#float"
10
+ end
11
+
12
+ def self.string
13
+ @string ||= coerce "http://www.w3.org/2001/XMLSchema#string"
14
+ end
15
+
16
+ def self.coerce(string_or_nil)
17
+ if string_or_nil.nil? || string_or_nil == ''
18
+ the_null_encoding
19
+ else
20
+ new string_or_nil
21
+ end
22
+ end
23
+
24
+ class Null
25
+ def to_s
26
+ ''
27
+ end
28
+
29
+ def format_as_n3(content)
30
+ "\"#{content}\""
31
+ end
32
+
33
+ def format_as_trix(content)
34
+ "<plainLiteral>#{content}</plainLiteral>"
35
+ end
36
+
37
+ def inspect
38
+ "<theRena::TypeLiteral::Encoding::Null>"
39
+ end
40
+
41
+ def xmlliteral?
42
+ false
43
+ end
44
+ end
45
+
46
+ def self.the_null_encoding
47
+ @the_null_encoding ||= Null.new
48
+ end
49
+
50
+ attr_reader :value
51
+ def initialize(value)
52
+ @value = value
53
+ end
54
+
55
+ def should_quote?
56
+ @value != self.class.integer.to_s
57
+ end
58
+
59
+ def ==(other)
60
+ case other
61
+ when String
62
+ other == @value
63
+ when self.class
64
+ other.value == @value
65
+ else
66
+ false
67
+ end
68
+ end
69
+
70
+ def hash
71
+ @value.hash
72
+ end
73
+
74
+ def to_s
75
+ @value
76
+ end
77
+
78
+ def format_as_n3(content)
79
+ quoted_content = should_quote? ? "\"#{content}\"" : content
80
+ "#{quoted_content}^^<#{value}>"
81
+ end
82
+
83
+ def format_as_trix(value)
84
+ "<typedLiteral datatype=\"#{@value}\">#{value}</typedLiteral>"
85
+ end
86
+
87
+ def xmlliteral?
88
+ @value == "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"
89
+ end
7
90
  end
8
- end
9
-
10
- def == (obj)
11
- if obj.class == Literal && obj.contents == @contents && (obj.lang == @lang || (obj.lang == nil && @lang == nil))
12
- true
13
- else
14
- false
91
+
92
+ class Language < Encoding
93
+ def initialize(string)
94
+ @value = string.downcase
95
+ end
96
+
97
+ def clean(string)
98
+ case string
99
+ when "eng"; "en"
100
+ else string
101
+ end
102
+ end
103
+
104
+ def format_as_n3(contents)
105
+ "\"#{contents}\"@#{@value}"
106
+ end
107
+
108
+ def format_as_trix(contents)
109
+ "<plainLiteral xml:lang=\"#{@value}\">#{contents}</plainLiteral>"
110
+ end
111
+
112
+ def == (other)
113
+ case other
114
+ when String
115
+ other == @value
116
+ when self.class
117
+ other.value == @value
118
+ end
119
+ end
15
120
  end
16
- end
17
-
18
- def to_n3
19
- out = "\"" + @contents + "\""
20
- out += "@" + @lang if @lang != nil
21
- out += "^^" + @encoding if @encoding != nil
22
- return out
23
- end
24
-
25
- def to_ntriples
26
- return self.to_n3
27
- end
28
121
 
29
- def to_trix
30
- if @lang != nil && @lang != false
31
- out = "<plainLiteral xml:lang=\"" + @lang + "\">"
32
- else
33
- out = "<plainLiteral>"
122
+ attr_accessor :contents, :encoding
123
+ def initialize(contents, encoding)
124
+ @contents = contents.to_s
125
+ unless encoding.is_a?(Encoding) || encoding.is_a?(Encoding::Null)
126
+ raise TypeError, "#{encoding.inspect} should be an instance of Encoding"
127
+ end
128
+ @encoding = encoding
34
129
  end
35
- out += @contents
36
- out += "</plainLiteral>"
37
- return out
38
- end
39
-
40
- end
41
130
 
42
- class TypedLiteral < Literal
43
- attr_accessor :contents, :encoding
44
- def initialize(contents, encoding)
45
- @contents = contents
46
- @encoding = encoding
47
- if @encoding == "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"
48
- @xmlliteral = true
49
- else
50
- @xmlliteral = false
131
+ def self.untyped(contents, language = nil)
132
+ new(contents, Language.coerce(language))
51
133
  end
52
- end
53
-
54
- def == (obj)
55
- if obj.class == TypedLiteral && obj.contents == @contents && obj.encoding == @encoding
56
- return true
57
- else
58
- return false
134
+
135
+ def self.typed(contents, encoding)
136
+ new(contents, Encoding.coerce(encoding))
59
137
  end
60
- end
61
-
62
- def to_n3
63
- if @encoding == "http://www.w3.org/2001/XMLSchema#int"
64
- out = @contents.to_s
65
- else
66
- out = "\"" + @contents.to_s + "\""
67
- end
68
- out += "^^<" + @encoding + ">" if @encoding != nil
69
- return out
70
- end
71
-
72
- def to_trix
73
- "<typedLiteral datatype=\"" + @encoding + "\">" + @contents + "</typedLiteral>"
74
- end
75
-
76
- def xmlliteral?
77
- @xmlliteral
78
- end
79
-
80
- def infer!
81
- if @contents.class == Fixnum
82
- @encoding = "http://www.w3.org/2001/XMLSchema#int"
83
- elsif @contents.class == Float
84
- @encoding = "http://www.w3.org/2001/XMLSchema#float"
85
- else
86
- @encoding = "http://www.w3.org/2001/XMLSchema#string"
138
+
139
+ def self.build_from(object)
140
+ new(object.to_s, infer_encoding_for(object))
141
+ end
142
+
143
+ def self.infer_encoding_for(object)
144
+ case object
145
+ when Integer; Encoding.integer
146
+ when Float; Encoding.float
147
+ else Encoding.string
148
+ end
149
+ end
150
+
151
+ require 'whatlanguage'
152
+ unless WhatLanguage.nil?
153
+ def self.infer_language_for(object)
154
+ inferred_lang = object.language
155
+ case inferred_lang
156
+ when :dutch; Language.new("nl")
157
+ when :english; Language.new("en")
158
+ when :farsi; Langauge.new("fa")
159
+ when :french; Language.new("fr")
160
+ when :german; Language.new("de")
161
+ when :pinyin; Language.new("zh-CN")
162
+ when :portugese; Language.new("pt")
163
+ when :russian; Language.new("ru")
164
+ when :spanish; Language.new("es")
165
+ when :swedish; Language.new("sv")
166
+ end
167
+ end
168
+
169
+ def self.build_from_language(object)
170
+ new(object.to_s, infer_language_for(object))
171
+ end
172
+ end
173
+
174
+ class << self
175
+ protected :new
176
+ end
177
+
178
+ def == (obj)
179
+ obj.is_a?(self.class) && obj.contents == @contents && obj.encoding == @encoding
180
+ end
181
+
182
+ def to_n3
183
+ encoding.format_as_n3(@contents)
184
+ end
185
+
186
+ ## alias_method breaks subclasses! Beware! Here be dragons!
187
+ def to_ntriples
188
+ to_n3
189
+ end
190
+
191
+ def to_trix
192
+ encoding.format_as_trix(@contents)
193
+ end
194
+
195
+ def xmlliteral?
196
+ encoding.xmlliteral?
197
+ end
198
+
199
+ def to_s
200
+ @contents.to_s
201
+ end
202
+
203
+ def lang
204
+ encoding.is_a?(Language) ? encoding : nil
87
205
  end
88
206
  end
89
- end
207
+ end
@@ -0,0 +1,129 @@
1
+ grammar N3Grammer
2
+ rule document
3
+ statements
4
+ end
5
+
6
+ rule statements
7
+ (space / (statement / directive) space* ('.' space*)? )*
8
+ end
9
+
10
+ rule statement
11
+ subject space+ property_list
12
+ end
13
+
14
+ rule subject
15
+ node
16
+ end
17
+
18
+ rule verb
19
+ ">-" prop "->" # has xxx of
20
+ / "<-" prop "<-" # is xxx of
21
+ # / # / operator # has operator:xxx of??? NOT IMPLMENTED
22
+ / prop # has xxx of -- shorthand
23
+ # / "has" prop # has xxx of
24
+ # / "is" prop "of" # is xxx of
25
+ / "a" # has rdf:type of
26
+ # / "=" # has daml:equivaent of
27
+ end
28
+
29
+ rule prop
30
+ node
31
+ end
32
+
33
+ rule node
34
+ uri_ref2 / anonnode / 'this'
35
+ end
36
+
37
+ rule anonnode
38
+ "[" space* property_list space* "]" # something which ...
39
+ / "{" statementlist "}" # the statementlist itself as a resource
40
+ / "(" nodelist ")" {
41
+ def anonnode; true; end
42
+ }
43
+ end
44
+
45
+ rule property_list
46
+ verb space+ object_list space* ";" space+ property_list
47
+ / verb space+ object_list
48
+ / ":-" anonnode #to allow two anonymous forms to be given eg [ a :Truth; :- { :sky :color :blue } ] )
49
+ / ":-" anonnode ";" property_list
50
+ / '.'
51
+ end
52
+
53
+ rule object_list
54
+ object "," space* object_list / object
55
+ end
56
+
57
+ rule directive
58
+ '@prefix' space+ nprefix:nprefix? ':' space+ uri_ref2:uri_ref2 {
59
+ def directive; true; end
60
+ }
61
+ end
62
+
63
+ rule uri_ref2
64
+ qname / "<" uri:URI_Reference ">"
65
+ end
66
+
67
+ rule qname
68
+ nprefix ":" localname / ':' localname
69
+ end
70
+
71
+ rule object
72
+ subject / literal
73
+ end
74
+
75
+ rule literal
76
+ (string1 / string2) ("^^<" uri:URI_Reference ">" / "@" [a-z]+ )?
77
+ end
78
+
79
+ rule localname
80
+ fragid
81
+ end
82
+
83
+ rule URI_Reference
84
+ [^{}<>]*
85
+ end
86
+
87
+ rule nprefix
88
+ ((alpha / "_") alphanumeric*)
89
+ end
90
+
91
+ rule fragid
92
+ alpha alphanumeric*
93
+ end
94
+
95
+ rule alpha
96
+ [a-zA-Z]
97
+ end
98
+
99
+ rule alphanumeric
100
+ alpha / [0-9] / "_"
101
+ end
102
+
103
+ rule space
104
+ [ \t\n\r]+ / comment
105
+ end
106
+
107
+ rule comment
108
+ '#' (![\n\r] .)*
109
+ end
110
+
111
+ # " constant-value-with-escaping "
112
+ rule string1
113
+ '"' string1_char+ '"'
114
+ end
115
+
116
+ rule string1_char
117
+ !["] .
118
+ end
119
+
120
+ # """ constant value with escaping including single or double occurences of quotes and/or newlines """
121
+ rule string2
122
+ '"""' string2_char* '"""'
123
+ end
124
+
125
+ rule string2_char
126
+ !'"""' . # something like this; need to think about it some more
127
+ end
128
+
129
+ end
@@ -0,0 +1,145 @@
1
+ require 'rena/graph'
2
+ require 'treetop'
3
+
4
+ Treetop.load(File.join(File.dirname(__FILE__), "n3_grammar"))
5
+
6
+ module Rena
7
+ class N3Parser
8
+ attr_accessor :graph
9
+
10
+ ##
11
+ # Creates a new parser for N3 (or Turtle).
12
+ #
13
+ # @param [String] n3_str the Notation3/Turtle string
14
+ # @param [String] uri the URI of the document
15
+ #
16
+ # @author Patrick Sinclair (metade)
17
+ def initialize(n3_str, uri=nil)
18
+ @uri = Addressable::URI.parse(uri) unless uri.nil?
19
+ parser = N3GrammerParser.new
20
+ document = parser.parse(n3_str)
21
+ if document
22
+ @graph = Graph.new
23
+ process_directives(document)
24
+ process_statements(document)
25
+ else
26
+ parser.terminal_failures.each do |tf|
27
+ puts "Expected #{tf.expected_string.inspect} (#{tf.index})- '#{n3_str[tf.index,10].inspect}'"
28
+ end
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def process_directives(document)
35
+ directives = document.elements.find_all { |e| e.elements.first.respond_to? :directive }
36
+ directives.map! { |d| d.elements.first }
37
+ directives.each { |d| namespace(d.uri_ref2.uri.text_value, d.nprefix.text_value) }
38
+ end
39
+
40
+ def namespace(uri, short)
41
+ short = '__local__' if short == ''
42
+ @graph.namespace(uri, short)
43
+ end
44
+
45
+ def process_statements(document)
46
+ subjects = document.elements.find_all { |e| e.elements.first.respond_to? :subject }
47
+ subjects.map! { |s| s.elements.first }
48
+ subjects.each do |s|
49
+ subject = process_node(s.subject)
50
+ properties = process_properties(s.property_list)
51
+ properties.each do |p|
52
+ predicate = process_verb(p.verb)
53
+ objects = process_objects(p.object_list)
54
+ objects.each { |object| triple(subject, predicate, object) }
55
+ end
56
+ end
57
+ end
58
+
59
+ def triple(subject, predicate, object)
60
+ @graph.add_triple(subject, predicate, object)
61
+ end
62
+
63
+ def process_anonnode(anonnode)
64
+ bnode = BNode.new
65
+ properties = process_properties(anonnode.property_list)
66
+ properties.each do |p|
67
+ predicate = process_node(p.verb)
68
+ objects = process_objects(p.object_list)
69
+ objects.each { |object| triple(bnode, predicate, object) }
70
+ end
71
+ bnode
72
+ end
73
+
74
+ def process_verb(verb)
75
+ return URIRef.new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') if (verb.text_value=='a')
76
+ return process_node(verb)
77
+ end
78
+
79
+ def process_node(node)
80
+ if (node.respond_to? :uri)
81
+ URIRef.new(node.uri.text_value)
82
+ else
83
+ prefix = (node.respond_to? :nprefix) ? node.nprefix.text_value : nil
84
+ localname = node.localname.text_value
85
+ build_uri(prefix, localname)
86
+ end
87
+ end
88
+
89
+ def process_properties(properties)
90
+ result = []
91
+ result << properties if (properties.respond_to? :verb)
92
+ result << process_properties(properties.property_list) if (properties.respond_to? :property_list)
93
+ result.flatten
94
+ end
95
+
96
+ def process_objects(objects)
97
+ result = []
98
+ if (objects.respond_to? :object)
99
+ result << process_object(objects.object)
100
+ else
101
+ result << process_object(objects)
102
+ end
103
+ result << process_objects(objects.object_list) if (objects.respond_to? :object_list)
104
+ result.flatten
105
+ end
106
+
107
+ def process_object(object)
108
+ if (object.respond_to? :localname or object.respond_to? :uri)
109
+ process_node(object)
110
+ elsif (object.respond_to? :property_list)
111
+ process_anonnode(object)
112
+ else
113
+ process_literal(object)
114
+ end
115
+ end
116
+
117
+ def process_literal(object)
118
+ encoding, language = nil, nil
119
+ string, type = object.elements
120
+
121
+ unless type.elements.nil?
122
+ if (type.elements[0].text_value=='@')
123
+ language = type.elements[1].text_value
124
+ else
125
+ encoding = type.elements[1].text_value
126
+ end
127
+ end
128
+
129
+ if (encoding.nil?)
130
+ Literal.untyped(string.elements[1].text_value, language)
131
+ else
132
+ Literal.typed(string.elements[1].text_value, encoding)
133
+ end
134
+ end
135
+
136
+ def build_uri(prefix, localname)
137
+ prefix = '__local__' if prefix.nil?
138
+ if (prefix=='_')
139
+ BNode.new(localname)
140
+ else
141
+ @graph.nsbinding[prefix].send(localname)
142
+ end
143
+ end
144
+ end
145
+ end