bel_parser 1.0.0.alpha.16 → 1.0.0.alpha.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e827bc3f99b0c849e302bd2f32debd794abf423
4
- data.tar.gz: e18d99921f436e6eb6d684230252d3c213d470da
3
+ metadata.gz: 21d0de137c850359607608e5cdca2a4481934fd5
4
+ data.tar.gz: aebe4a51435a51ee91d410a2c5ff0753ec3d51d2
5
5
  SHA512:
6
- metadata.gz: 6c25495a94d389796b6a6f086527fc1c0ce6d6a6850966eaa169a6961d970f853ff03ec201022fd86609011ed0a3dfd76670e88ef4afdd18c749b43a02aa56ab
7
- data.tar.gz: a3fbb92d0168fe0d7373ba01cc9a986f8127be586aefe31d3a93117ff72506ea406daa073979fbbaa5af5ae98360858ed1edf1289550a485c950fb42736894a4
6
+ metadata.gz: 51d92527013676307ee3307496f1282fe838a9f57b138e1d74d6dcdb49cd7061fd913c26111422f9e1fcad3c61dcbd1ead176996ec90e20acc2e272b49de710b
7
+ data.tar.gz: edf6a891d9d6d9ba08dcef2cf4f6090cba96b040b931c8ee7aa39296bc7a6a305b81b45c2e617254b9b293a92a0e90db80756327b2b6e90430b1c8b68caeb184
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.alpha.16
1
+ 1.0.0.alpha.17
data/bin/bel2_validator CHANGED
@@ -9,7 +9,6 @@ unless ARGV.first
9
9
  USAGE
10
10
  exit 1
11
11
  end
12
- namespaces = Hash[ARGV[1..-1].map { |ns| ns.split('=') }]
13
12
 
14
13
  def syntax_results(results)
15
14
  results.select do |res|
@@ -25,9 +24,18 @@ end
25
24
 
26
25
  require 'bel_parser'
27
26
  require 'bel_parser/expression/validator'
28
- require 'bel_parser/resource/resource_file_reader'
27
+ require 'bel_parser/resource/resource_url_reader'
28
+
29
+ resource_reader = BELParser::Resource::ResourceURLReader.new(true)
30
+ namespaces =
31
+ Hash[
32
+ ARGV.map do |ns|
33
+ prefix, identifier = ns.split('=')
34
+ dataset = resource_reader.retrieve_resource(identifier)
35
+ dataset ? [prefix, dataset] : nil
36
+ end.compact
37
+ ]
29
38
 
30
- resource_reader = BELParser::Resource::ResourceFileReader.new
31
39
  BELParser::Expression::Validator
32
40
  .new(ARGV.first, namespaces, resource_reader)
33
41
  .each($stdin) do |(line_number, line, ast, results)|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(
4
4
 
5
5
  require 'optparse'
6
6
  require 'bel_parser'
7
- require 'bel_parser/resource/resource_file_reader'
7
+ require 'bel_parser/resource/resource_url_reader'
8
8
 
9
9
  options = {
10
10
  spec: BELParser::Language.specification(
@@ -37,6 +37,14 @@ OptionParser.new do |opts|
37
37
 
38
38
  options[:spec] = BELParser::Language.specification(spec)
39
39
  end
40
+
41
+ opts.on(
42
+ '-r',
43
+ '--[no-]reuse-resource-databases',
44
+ 'Enable to reuse resource databases if they exist.') do |reuse|
45
+
46
+ options[:reuse] = reuse
47
+ end
40
48
  end.parse!
41
49
 
42
50
  file, spec = options.values_at(:file, :spec)
@@ -70,7 +78,7 @@ SYN_ERR = BELParser::Language::Syntax::SyntaxError
70
78
  SYN_WARN = BELParser::Language::Syntax::SyntaxWarning
71
79
  SEM_WARN = BELParser::Language::Semantics::SemanticsWarning
72
80
 
73
- rr = BELParser::Resource::ResourceFileReader.new
81
+ rr = BELParser::Resource::ResourceURLReader.new(options[:reuse])
74
82
  namespaces = Hash[
75
83
  ARGV.map do |ns|
76
84
  prefix, identifier = ns.split('=')
@@ -80,7 +88,7 @@ namespaces = Hash[
80
88
  ]
81
89
 
82
90
  initial_state = {
83
- resource_reader: BELParser::Resource::ResourceFileReader.new,
91
+ resource_reader: rr,
84
92
  specification: spec,
85
93
  namespace_definitions: namespaces
86
94
  }
@@ -49,9 +49,9 @@ if __FILE__ == $PROGRAM_NAME
49
49
  exit 1
50
50
  end
51
51
 
52
- require 'bel_parser/resource/resource_file_reader'
52
+ require 'bel_parser/resource/resource_url_reader'
53
53
 
54
- resource_reader = BELParser::Resource::ResourceFileReader.new
54
+ resource_reader = BELParser::Resource::ResourceURLReader.new
55
55
  namespaces =
56
56
  Hash[
57
57
  ARGV[1..-1]
@@ -15,61 +15,75 @@ module BELParser
15
15
  @locks ||= Concurrent::Hash.new
16
16
  end
17
17
 
18
+ def load_threads
19
+ @load_threads ||= Concurrent::Hash.new
20
+ end
21
+
22
+ def load_values(identifier)
23
+ lock = locks[identifier] ||= Mutex.new
24
+ if identifier.include?('taxonomy')
25
+ puts "load_all_values, try lock..."
26
+ end
27
+ if lock.try_lock
28
+ load_threads[identifier] = Thread.new do
29
+ value_hash = {
30
+ :name => {},
31
+ :identifier => {},
32
+ :title => {},
33
+ :synonyms => {}
34
+ }
35
+ retrieve_values_from_resource(identifier).each do |concept|
36
+ value_hash[:name][concept.name] = concept
37
+ value_hash[:identifier][concept.identifier] = concept
38
+ value_hash[:title][concept.title] = concept
39
+ concept.synonyms.each do |synonym|
40
+ value_hash[:synonyms][synonym] = concept
41
+ end
42
+ end
43
+ resources[identifier] = value_hash
44
+ lock.unlock
45
+ end
46
+ end
47
+ end
48
+
18
49
  def retrieve_resource(resource_identifier)
19
50
  if !resources.key?(resource_identifier)
20
51
  load_all_values(resource_identifier)
21
52
  end
22
- super
23
53
  end
24
54
 
25
55
  def retrieve_value_from_resource(resource_identifier, value)
26
56
  if !resources.key?(resource_identifier)
27
57
  load_all_values(resource_identifier)
58
+ if load_threads.key?(resource_identifier)
59
+ load_thread = load_threads[resource_identifier]
60
+ load_thread.join unless load_thread == Thread.current
61
+ end
28
62
  end
29
63
 
30
64
  concepts = resources[resource_identifier]
31
- return super unless concepts
65
+ return nil unless concepts
32
66
  CACHE_KEYS.each do |key|
33
67
  cached_concept = concepts[key].fetch(value, nil)
34
68
  return cached_concept if cached_concept
35
69
  end
36
-
37
70
  nil
38
71
  end
39
72
 
40
73
  def retrieve_values_from_resource(resource_identifier)
41
74
  if !resources.key?(resource_identifier)
42
75
  load_all_values(resource_identifier)
76
+ if load_threads.key?(resource_identifier)
77
+ load_thread = load_threads[resource_identifier]
78
+ load_thread.join unless load_thread == Thread.current
79
+ end
43
80
  end
44
81
 
45
82
  concepts = resources[resource_identifier]
46
- return super unless concepts
83
+ return nil unless concepts
47
84
  concepts[:name].values
48
85
  end
49
86
 
50
- def load_all_values(identifier)
51
- lock = locks[identifier] ||= Mutex.new
52
- if lock.try_lock
53
- Thread.new do
54
- value_hash = {
55
- :name => {},
56
- :identifier => {},
57
- :title => {},
58
- :synonyms => {}
59
- }
60
- retrieve_values_from_resource(identifier).each do |concept|
61
- value_hash[:name][concept.name] = concept
62
- value_hash[:identifier][concept.identifier] = concept
63
- value_hash[:title][concept.title] = concept
64
- concept.synonyms.each do |synonym|
65
- value_hash[:synonyms][synonym] = concept
66
- end
67
- end
68
- resources[identifier] = value_hash
69
- lock.unlock
70
- end
71
- end
72
- end
73
87
  end
74
88
  end
75
89
  end
@@ -0,0 +1,21 @@
1
+ require_relative 'dataset'
2
+
3
+ # FileResource is a {Dataset} description obtained from a Annotation or
4
+ # Namespace file.
5
+ module BELParser
6
+ module Resource
7
+ class FileResource
8
+ include Dataset
9
+
10
+ attr_reader :identifier, :domain, :keyword, :name, :types
11
+
12
+ def initialize(identifier, domain, keyword, name, type)
13
+ @identifier = identifier.to_s
14
+ @domain = domain.to_s
15
+ @keyword = keyword.to_s
16
+ @name = name.to_s
17
+ @types = [type]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'value'
2
+
3
+ # FileResourceValue is a {Value} obtained from a Annotation or Namespace
4
+ # file.
5
+ module BELParser
6
+ module Resource
7
+ class FileResourceValue
8
+ include Value
9
+
10
+ attr_reader :dataset, :name, :encodings
11
+
12
+ def initialize(dataset, name, encodings)
13
+ @dataset = dataset
14
+ @name = name
15
+ @encodings =
16
+ if dataset.annotation_resource? && !dataset.namespace_resource?
17
+ nil
18
+ else
19
+ encodings.chars.map(&:to_sym)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,7 +3,7 @@ require 'concurrent/hash'
3
3
  module BELParser
4
4
  module Resource
5
5
  # LRUCache implements a least recently used cache. This implementation was
6
- # initially copied from https://github.com/SamSaffron/lru_redux.
6
+ # adapted from https://github.com/SamSaffron/lru_redux.
7
7
  class LRUCache
8
8
  def initialize(max_size)
9
9
  raise ArgumentError.new(:max_size) if max_size < 1
@@ -4,30 +4,29 @@ module BELParser
4
4
  module Resource
5
5
  module LRUReader
6
6
 
7
- LRU_MAX_SIZE = 500
7
+ LRU_MAX_SIZE = 2000
8
8
  private_constant :LRU_MAX_SIZE
9
9
 
10
- def resources
11
- @resources ||= Concurrent::Hash.new
12
- end
13
-
14
10
  def retrieve_resource(resource_identifier)
15
- if !resources.key?(resource_identifier)
16
- resources[resource_identifier] = LRUCache.new(LRU_MAX_SIZE)
17
- end
18
- super
11
+ @resources ||= Hash.new { |hash, key| hash[key] = {} }
12
+ cached_dataset = @resources[resource_identifier][:dataset]
13
+ return cached_dataset if cached_dataset
14
+
15
+ resolved_dataset = super
16
+ @resources[resource_identifier][:dataset] = resolved_dataset
17
+ @resources[resource_identifier][:values] = LRUCache.new(LRU_MAX_SIZE)
18
+ resolved_dataset
19
19
  end
20
20
 
21
21
  def retrieve_value_from_resource(resource_identifier, value)
22
- if !resources.key?(resource_identifier)
23
- resources[resource_identifier] = LRUCache.new(LRU_MAX_SIZE)
24
- end
25
-
26
- concepts = resources[resource_identifier]
27
- concepts.getset(value) { super }
22
+ retrieve_resource(resource_identifier)
23
+ @resources[resource_identifier][:values].getset(value) {
24
+ super
25
+ }
28
26
  end
29
27
 
30
28
  def retrieve_values_from_resource(resource_identifier)
29
+ retrieve_resource(resource_identifier)
31
30
  super
32
31
  end
33
32
  end
@@ -0,0 +1,160 @@
1
+ require 'base64'
2
+ require 'digest'
3
+ require 'gdbm'
4
+ require 'net/http'
5
+ require 'tempfile'
6
+ require 'uri'
7
+ require_relative 'reader'
8
+ require_relative 'file_resource'
9
+ require_relative 'file_resource_value'
10
+
11
+ module BELParser
12
+ module Resource
13
+ # ResourceURLReader retrieves {Dataset datasets} and {Value values} from
14
+ # Annotation (i.e. belanno extension) and Namespace (i.e. belns extension)
15
+ # files. Value and encoding are stored in GDBM database files to reduce the
16
+ # runtime memory usage (22 resources loaded, totaling 100MB memory usage).
17
+ #
18
+ # Only supports resource identifiers with an HTTP or HTTPS scheme.
19
+ class ResourceURLReader
20
+ include Reader
21
+
22
+ DEFAULT_RESOURCE_VALUE_DELIMITER = '|'
23
+ private_constant :DEFAULT_RESOURCE_VALUE_DELIMITER
24
+
25
+ def initialize(reuse_database_files = false)
26
+ @resources = {}
27
+ @datasets = ::GDBM.new(_temporary_datasets_file)
28
+ @reuse = reuse_database_files
29
+ end
30
+
31
+ def retrieve_resource(resource_identifier)
32
+ read_resource(resource_identifier)[:dataset]
33
+ end
34
+
35
+ def retrieve_value_from_resource(resource_identifier, value)
36
+ resource = read_resource(resource_identifier)
37
+ encoding = resource[:values][value]
38
+ return nil unless encoding
39
+ FileResourceValue.new(resource[:dataset], value, encoding)
40
+ end
41
+
42
+ def retrieve_values_from_resource(resource_identifier)
43
+ resource = read_resource(resource_identifier)
44
+ dataset = resource[:dataset]
45
+ resource[:values].lazy.map do |value, encoding|
46
+ FileResourceValue.new(dataset, value, encoding)
47
+ end
48
+ end
49
+
50
+ protected
51
+
52
+ def read_resource(url)
53
+ # return cached resource if present
54
+ resource = @resources[url]
55
+ return resource if resource
56
+
57
+ # read url
58
+ content = http_get(url)
59
+ unless content
60
+ # cache and return empty resource if not resolvable
61
+ return @resources[url] = empty_resource
62
+ end
63
+
64
+ @resources[url] = create_resource(url, content.each_line)
65
+ end
66
+
67
+ def create_resource(url, line_enum)
68
+ delimiter = DEFAULT_RESOURCE_VALUE_DELIMITER
69
+ dataset = @datasets[url]
70
+ value_database_file = _temporary_database_file(url)
71
+ values = ::GDBM.new(value_database_file)
72
+
73
+ if @reuse && dataset && values.size > 0
74
+ warn(
75
+ <<-MSG.gsub(/^ {14}/, '')
76
+ Warning - Reusing value database.
77
+ URL: #{url}
78
+ File: #{value_database_file}
79
+ MSG
80
+ )
81
+ return {
82
+ dataset: FileResource.new(url, *dataset.split('//')),
83
+ values: values
84
+ }
85
+ end
86
+
87
+ value_section = false
88
+ type, name, keyword, domain = nil
89
+ line_enum.each do |line|
90
+ line.strip!
91
+ case
92
+ when line =~ /^#{Regexp.escape('[AnnotationDefinition]')}/
93
+ type = Dataset::ANNOTATION
94
+ when line =~ /^#{Regexp.escape('[Namespace]')}/
95
+ type = Dataset::NAMESPACE
96
+ when line =~ /^NameString *= *(.*)$/
97
+ name = Regexp.last_match[1]
98
+ when line =~ /^Keyword *= *(.*)$/
99
+ keyword = Regexp.last_match[1]
100
+ when line =~ /^DomainString *= *(.*)$/
101
+ domain = Regexp.last_match[1]
102
+ when line =~ /^DelimiterString *=(.*)$/
103
+ delimiter = Regexp.last_match[1]
104
+ when line =~ /^#{Regexp.escape('[Values]')}/
105
+ dataset = FileResource.new(url, domain, keyword, name, type)
106
+ value_section = true
107
+ when value_section
108
+ value, encoding = line.strip.split(delimiter)
109
+ values[value.to_s] = encoding.to_s
110
+ end
111
+ end
112
+
113
+ resource = {
114
+ dataset: FileResource.new(url, domain, keyword, name, type),
115
+ values: values
116
+ }
117
+ @datasets[url] = [domain, keyword, name, type].join('//')
118
+ resource
119
+ end
120
+
121
+ def empty_resource
122
+ { dataset: nil, values: {} }
123
+ end
124
+
125
+ def http_get(url)
126
+ begin
127
+ _get(URI.parse(url))
128
+ rescue URI::InvalidURIError, SocketError
129
+ return nil
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def _get(url, &block)
136
+ Net::HTTP.start(url.host, url.port) do |http|
137
+ http.request(Net::HTTP::Get.new(url)) do |response|
138
+ return response.read_body
139
+ end
140
+ end
141
+ end
142
+
143
+ def _hash_url(url)
144
+ Base64.encode64(Digest::SHA1.digest(url)).delete("/=\n")
145
+ end
146
+
147
+ def _temporary_datasets_file
148
+ resource_directory = File.join(Dir.tmpdir, 'belresources')
149
+ FileUtils.mkdir_p(resource_directory)
150
+ File.join(resource_directory, 'datasets.gdbm')
151
+ end
152
+
153
+ def _temporary_database_file(url)
154
+ resource_directory = File.join(Dir.tmpdir, 'belresources')
155
+ FileUtils.mkdir_p(resource_directory)
156
+ File.join(resource_directory, "#{_hash_url(url)}.gdbm")
157
+ end
158
+ end
159
+ end
160
+ end
@@ -98,10 +98,12 @@ end
98
98
  if __FILE__ == $PROGRAM_NAME
99
99
  $LOAD_PATH.unshift(
100
100
  File.join(File.expand_path(File.dirname(__FILE__)), '..', '..'))
101
+
101
102
  require 'bel_parser/language'
102
- require 'bel_parser/resource/resource_file_reader'
103
+ require 'bel_parser/resource/resource_url_reader'
104
+
103
105
  initial_state = {
104
- resource_reader: BELParser::Resource::ResourceFileReader.new,
106
+ resource_reader: BELParser::Resource::ResourceURLReader.new,
105
107
  specification: BELParser::Language.specification(
106
108
  BELParser::Language.latest_supported_version
107
109
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bel_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.16
4
+ version: 1.0.0.alpha.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Bargnesi
@@ -304,12 +304,13 @@ files:
304
304
  - lib/bel_parser/resource/dataset.rb
305
305
  - lib/bel_parser/resource/eager_reader.rb
306
306
  - lib/bel_parser/resource/eager_sparql_reader.rb
307
- - lib/bel_parser/resource/http_cache.rb
307
+ - lib/bel_parser/resource/file_resource.rb
308
+ - lib/bel_parser/resource/file_resource_value.rb
308
309
  - lib/bel_parser/resource/jena_tdb_reader.rb
309
310
  - lib/bel_parser/resource/lru_cache.rb
310
311
  - lib/bel_parser/resource/lru_reader.rb
311
312
  - lib/bel_parser/resource/reader.rb
312
- - lib/bel_parser/resource/resource_file_reader.rb
313
+ - lib/bel_parser/resource/resource_url_reader.rb
313
314
  - lib/bel_parser/resource/sparql_reader.rb
314
315
  - lib/bel_parser/resource/value.rb
315
316
  - lib/bel_parser/script.rb
@@ -1,89 +0,0 @@
1
- require 'base64'
2
- require 'concurrent/hash'
3
- require 'digest'
4
- require 'fileutils'
5
- require 'net/http'
6
- require 'tempfile'
7
-
8
- module BELParser
9
- module Resource
10
- class HTTPCache
11
-
12
- # Lock (per URL) ensures concurrent retrieval/caching is thread-safe.
13
- URL_LOCKS = Concurrent::Hash.new do |hash, key|
14
- hash[key] = Mutex.new
15
- end
16
- private_constant :URL_LOCKS
17
-
18
- def initialize(base_dir="#{Dir.tmpdir}/bel-resources")
19
- @base_dir = FileUtils.mkdir_p(base_dir).first
20
- end
21
-
22
- def get(url)
23
- cached_url_path = File.join(@base_dir, hash_url(url))
24
- URL_LOCKS[url].synchronize do
25
- if File.exists?(cached_url_path)
26
- if block_given?
27
- File.open(cached_url_path) do |cached_file|
28
- yield cached_file
29
- end
30
- else
31
- File.open(cached_url_path)
32
- end
33
- else
34
- uri = URI.parse(url)
35
- begin
36
- Net::HTTP.start(uri.host, uri.port) do |http|
37
- http.request(Net::HTTP::Get.new(uri)) do |response|
38
-
39
- if block_given?
40
- if response.is_a?(Net::HTTPOK)
41
- cached_file = File.open(cached_url_path, 'w')
42
- response.read_body do |chunk|
43
- cached_file.write(chunk)
44
- yield StringIO.new(chunk)
45
- end
46
- else
47
- yield nil
48
- end
49
- else
50
- if response.is_a?(Net::HTTPOK)
51
- cached_file = File.open(cached_url_path, 'w')
52
- content = response.read_body
53
- cached_file.write(content)
54
- return StringIO.new(content)
55
- else
56
- return nil
57
- end
58
- end
59
- end
60
- end
61
- rescue SocketError
62
- if block_given?
63
- yield nil
64
- else
65
- return nil
66
- end
67
- ensure
68
- if defined? cached_file
69
- cached_file.close
70
- end
71
- end
72
- end
73
- end
74
- end
75
-
76
- protected
77
-
78
- def hash_url(url)
79
- Base64.encode64(Digest::SHA1.digest(url)).delete("/=\n")
80
- end
81
- end
82
- end
83
- end
84
-
85
- if __FILE__ == $PROGRAM_NAME
86
- BELParser::Resource::HTTPCache.new.get(ARGV.first) do |io|
87
- io.each_line { |line| puts line }
88
- end
89
- end
@@ -1,135 +0,0 @@
1
- require 'open-uri'
2
- require_relative 'reader'
3
- require_relative 'eager_reader'
4
- require_relative 'dataset'
5
- require_relative 'http_cache'
6
- require_relative 'value'
7
-
8
- module BELParser
9
- module Resource
10
- # ResourceFileReader retrieves {Dataset datasets} and {Value values} from
11
- # Annotation (i.e. belanno extension) and Namespace (i.e. belns extension)
12
- # files.
13
- #
14
- # Only supports resource identifiers with an HTTP or HTTPS scheme.
15
- class ResourceFileReader
16
- include Reader
17
- prepend EagerReader
18
-
19
- DEFAULT_RESOURCE_VALUE_DELIMITER = '|'
20
- private_constant :DEFAULT_RESOURCE_VALUE_DELIMITER
21
-
22
- def initialize
23
- @http_cache = HTTPCache.new
24
- end
25
-
26
- def retrieve_resource(resource_identifier)
27
- read_resource(resource_identifier)
28
- end
29
-
30
- def retrieve_value_from_resource(resource_identifier, value)
31
- file_resource = read_resource(resource_identifier)
32
-
33
- io = @http_cache.get(resource_identifier)
34
- delimiter = DEFAULT_RESOURCE_VALUE_DELIMITER
35
- io.each_line do |line|
36
- case line
37
- when /^DelimiterString *=(.*)/
38
- delimiter = Regexp.last_match[1]
39
- when /^#{Regexp.escape('[Values]')}/
40
- break
41
- end
42
- end
43
-
44
- value_match = "#{value}#{delimiter}"
45
- value_line = io.each_line.find do |line|
46
- line.start_with?(value_match)
47
- end
48
- return nil unless value_line
49
- value, encoding = value_line.strip.split(delimiter)
50
- FileResourceValue.new(file_resource, value, encoding)
51
- end
52
-
53
- def retrieve_values_from_resource(resource_identifier)
54
- file_resource = read_resource(resource_identifier)
55
-
56
- io = @http_cache.get(resource_identifier)
57
- delimiter = DEFAULT_RESOURCE_VALUE_DELIMITER
58
- io.each_line do |line|
59
- case line
60
- when /^DelimiterString *=(.*)/
61
- delimiter = Regexp.last_match[1]
62
- when /^#{Regexp.escape('[Values]')}/
63
- break
64
- end
65
- end
66
-
67
- io.each_line.map do |line|
68
- value, encoding = line.strip.split(delimiter)
69
- FileResourceValue.new(file_resource, value, encoding)
70
- end
71
- end
72
-
73
- private
74
-
75
- def read_resource(url)
76
- io = @http_cache.get(url)
77
- return nil unless io
78
-
79
- type, name, keyword, domain = nil
80
- io.each_line do |line|
81
- case line
82
- when /^#{Regexp.escape('[AnnotationDefinition]')}/
83
- type = Dataset::ANNOTATION
84
- when /^#{Regexp.escape('[Namespace]')}/
85
- type = Dataset::NAMESPACE
86
- when /^NameString *= *(.*)$/
87
- name = Regexp.last_match[1]
88
- when /^Keyword *= *(.*)$/
89
- keyword = Regexp.last_match[1]
90
- when /^DomainString *= *(.*)$/
91
- domain = Regexp.last_match[1]
92
- when /^#{Regexp.escape('[Values]')}/
93
- break
94
- end
95
- end
96
- FileResource.new(url, domain, keyword, name, type)
97
- end
98
-
99
- # FileResource is a {Dataset} description obtained from a Annotation or
100
- # Namespace file.
101
- class FileResource
102
- include Dataset
103
-
104
- attr_reader :identifier, :domain, :keyword, :name, :types
105
-
106
- def initialize(identifier, domain, keyword, name, type)
107
- @identifier = identifier.to_s
108
- @domain = domain.to_s
109
- @keyword = keyword.to_s
110
- @name = name.to_s
111
- @types = [type]
112
- end
113
- end
114
-
115
- # FileResourceValue is a {Value} obtained from a Annotation or Namespace
116
- # file.
117
- class FileResourceValue
118
- include Value
119
-
120
- attr_reader :dataset, :name, :encodings
121
-
122
- def initialize(dataset, name, encodings)
123
- @dataset = dataset
124
- @name = name
125
- @encodings =
126
- if dataset.annotation_resource? && !dataset.namespace_resource?
127
- nil
128
- else
129
- encodings.chars.map(&:to_sym)
130
- end
131
- end
132
- end
133
- end
134
- end
135
- end