spread2rdf 0.0.1pre.1 → 0.0.1

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.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile.ocra +6 -0
  3. data/VERSION +1 -1
  4. data/bin/spread2rdf +1 -1
  5. data/lib/spread2rdf/attributes.rb +1 -0
  6. data/lib/spread2rdf/cli.rb +128 -34
  7. data/lib/spread2rdf/coord.rb +49 -0
  8. data/lib/spread2rdf/mapping/cell.rb +105 -0
  9. data/lib/spread2rdf/mapping/column.rb +63 -0
  10. data/lib/spread2rdf/mapping/column_block.rb +23 -0
  11. data/lib/spread2rdf/mapping/default_cell_mappings.rb +26 -0
  12. data/lib/spread2rdf/mapping/element.rb +64 -0
  13. data/lib/spread2rdf/mapping/resource.rb +95 -0
  14. data/lib/spread2rdf/mapping/sheet.rb +80 -0
  15. data/lib/spread2rdf/mapping/spreadsheet.rb +56 -0
  16. data/lib/spread2rdf/mapping/statement.rb +22 -0
  17. data/lib/spread2rdf/mapping/worksheet.rb +12 -0
  18. data/lib/spread2rdf/namespace.rb +6 -2
  19. data/lib/spread2rdf/roo_helper.rb +45 -0
  20. data/lib/spread2rdf/schema/column.rb +37 -0
  21. data/lib/spread2rdf/{spreadsheet/sub_sheet.rb → schema/column_block.rb} +3 -2
  22. data/lib/spread2rdf/{spreadsheet → schema}/element.rb +12 -16
  23. data/lib/spread2rdf/schema/schema.rb +19 -0
  24. data/lib/spread2rdf/schema/sheet.rb +87 -0
  25. data/lib/spread2rdf/schema/sheet_dsl.rb +54 -0
  26. data/lib/spread2rdf/schema/spreadsheet.rb +49 -0
  27. data/lib/spread2rdf/schema/spreadsheet_dsl.rb +42 -0
  28. data/lib/spread2rdf/schema/statement_mapping_schema.rb +26 -0
  29. data/lib/spread2rdf/schema/worksheet.rb +47 -0
  30. data/lib/spread2rdf.rb +34 -2
  31. data/ontologies/unit-v1.1.ttl +8330 -0
  32. data/spread2rdf.gemspec +4 -2
  33. metadata +50 -26
  34. data/lib/spread2rdf/helper.rb +0 -14
  35. data/lib/spread2rdf/spreadsheet/column.rb +0 -48
  36. data/lib/spread2rdf/spreadsheet/column_mapping_context.rb +0 -156
  37. data/lib/spread2rdf/spreadsheet/coord.rb +0 -51
  38. data/lib/spread2rdf/spreadsheet/mapping_context.rb +0 -67
  39. data/lib/spread2rdf/spreadsheet/mapping_dsl.rb +0 -23
  40. data/lib/spread2rdf/spreadsheet/sheet.rb +0 -128
  41. data/lib/spread2rdf/spreadsheet/sheet_dsl.rb +0 -34
  42. data/lib/spread2rdf/spreadsheet/sheet_mapping_context.rb +0 -90
  43. data/lib/spread2rdf/spreadsheet/sub_sheet_mapping_context.rb +0 -55
  44. data/lib/spread2rdf/spreadsheet/worksheet.rb +0 -49
  45. data/lib/spread2rdf/spreadsheet.rb +0 -92
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzBlOGJjZDMyMjBjMjNmNDA5MTk3MmY1NjMzMmE2OWNiZGE3MTljYw==
4
+ NTJjZDkxNmJhNmM2ZjFmYjM4ZGJlZjE2MGQyZmZkNWMzMWI1NGQ4Yw==
5
5
  data.tar.gz: !binary |-
6
- Y2IxMjY2MDBjZDk1OGYxNjE2YjlmM2UyZGZkYTQ2NmZjNDk5MWYyYQ==
6
+ YjFmZjA5ZmZmOTk5ZWJjODAwOTgwZDNkZjkyYWY3NTgwMjllYzBkOA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODlkODhkZDQ1NzZmNGVhY2E0MGIwNDgyOWVmZDFkODkyYjJlYmNiZjYyMzlh
10
- ZmEzNjk4YjJiNjIyZjM1OTM2YTQ1ZGZlZDJjZTFhOTA1Mzc0ZWJlZTY4NjY1
11
- YmEyNGZmNGM1ZjBkYTMxMTNmZWQ2YTZkNzVkOTViMDA2Y2I0ZTk=
9
+ OTEzM2JjNjkyNTkyMGJiNDUwZTE1OTE0NjE4ZjcyZmNkZTk5MWFjMDYyYzU5
10
+ Nzk0NWU5MDVhMmIwYmJkNjFiMjA5ZmI5NjU1Yjg4NzMxNWM5Yjk3MzFjMTgy
11
+ MGRjMWJiN2VlMzU5OWNkYmNhMDkxZjNlN2ExOWUwN2ZhYmQzOGI=
12
12
  data.tar.gz: !binary |-
13
- MDExZWZiZjY4YjBlNDdkYzhkN2ExZjNmNTVhNWVkNGEwMDBmYzg0YTY0ZGM2
14
- Njk3ZmQ4NmU3MmY3MjAxYzkwZjkzZThjM2VhZWMzYjYyZmJjYjBjMTc0MTdi
15
- YzUwNzlhNTRhMjY0NDJiNzIxZTdiYTkzNTZlM2U0ZTBjZTNmODY=
13
+ N2MxZGQ4YjMxYmI2Y2IyN2NiMjFiN2U4NmRkZjA4NGJlMWNkNzgxYjg5MWU2
14
+ YTkyZmY1ZGM5YWIyZTkwMjFmODI5ZDUwZTc4ZWQ2ZmFlMzVmMzc3NGE1Nzcz
15
+ ZGIzZDBmMTA2MWRhNjJmZDJmMGY3NzM3NDEyOGNiODFlOTQwNGU=
data/Gemfile.ocra ADDED
@@ -0,0 +1,6 @@
1
+ # we need this dedicated Gemfile currently, due to this issue:
2
+ # https://github.com/larsch/ocra/issues/59
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ gem 'spread2rdf', '~> 0.0.1'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1pre.1
1
+ 0.0.1
data/bin/spread2rdf CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'spread2rdf'
3
- Spread2RDF::Cli.new.run
3
+ Spread2RDF::CLI.run
@@ -6,6 +6,7 @@ module Spread2RDF
6
6
  def attributes
7
7
  if superclass.respond_to?(:attributes) and
8
8
  (super_attributes = superclass.attributes).is_a? Hash
9
+ @attributes ||= {}
9
10
  @attributes.reverse_merge(super_attributes)
10
11
  else
11
12
  @attributes
@@ -1,63 +1,119 @@
1
1
  # coding: utf-8
2
+ require 'singleton'
2
3
 
3
4
  module Spread2RDF
4
5
  class Cli
5
- def initialize
6
+ include Singleton
7
+
8
+ attr_accessor :mapping_schema
9
+
10
+ def run(options = {})
11
+ @running = true
12
+ init(options)
6
13
  parse_command_line!
14
+ case
15
+ when compile? then compile(@mapping_schema)
16
+ else convert
17
+ end
18
+ self
19
+ rescue => e
20
+ if Spread2RDF.debug_mode
21
+ raise e
22
+ else
23
+ abort e.to_s
24
+ end
7
25
  end
8
26
 
9
- def run(schema_spec_file = nil)
10
- schema_spec_file ||= @options[:schema_spec_file]
11
- abort "No schema specification file given" if schema_spec_file.nil?
12
- abort "Couldn't find schema specification file #{schema_spec_file}" unless
13
- File.exist?(schema_spec_file)
14
- load schema_spec_file
15
- abort "No schema specification found" if Spreadsheet.definitions.empty?
16
- puts "Reading #{@input_file} ..."
17
- @table = Spreadsheet.definitions.first
18
- @table.read(@input_file)
19
- write_output
20
- self
27
+ def init(options)
28
+ @options = options
29
+ @input_file = @options.delete(:input_file) if @options[:input_file]
30
+ self.mapping_schema = @options.delete(:schema) if @options[:schema]
31
+ end
32
+ private :init
33
+
34
+ def running?
35
+ @running
36
+ end
37
+
38
+ def compile?
39
+ !!@options[:compile]
40
+ end
41
+
42
+ def mapping_schema=(schema)
43
+ @mapping_schema =
44
+ case schema
45
+ when nil then nil
46
+ when Schema::Spreadsheet then schema
47
+ when String
48
+ abort "no schema specification file given" if schema.nil?
49
+ abort "couldn't find schema specification file #{schema}" unless
50
+ File.exist?(schema)
51
+ load schema
52
+ abort "no schema specification found" if Schema.definitions.empty?
53
+ Schema.definitions.first
54
+ else raise ArgumentError
55
+ end
21
56
  end
22
57
 
23
58
  private
24
59
 
25
- # Parse command line options
26
- def parse_command_line!(options={})
27
- @options = options
60
+ def parse_command_line!
28
61
  optparse = OptionParser.new do |opts|
29
- opts.banner = 'Usage: spread2rdf [options] -s SPEC_FILE SPREAD_SHEET_FILE'
62
+ if mapping_schema
63
+ opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] SPREAD_SHEET_FILE"
64
+ else
65
+ opts.banner = 'Usage: spread2rdf [options] -s SPEC_FILE SPREAD_SHEET_FILE'
66
+ end
30
67
 
31
68
  opts.on( '-h', '--help', 'Display this information' ) do
32
69
  puts opts
33
70
  exit
34
71
  end
35
72
 
36
- @options[:output_dir] = '.'
37
- opts.on( '-o', '--output DIR', 'Output directory (default: current directory)' ) do |dir|
38
- abort "Output directory #{dir} doesn't exist" unless Dir.exist?(dir)
73
+ opts.on( '-v', '--version', 'Print version information' ) do
74
+ puts "Spread2RDF #{VERSION}"
75
+ exit
76
+ end
77
+
78
+ if not mapping_schema
79
+ opts.on( '-c', '--compile', 'Compile the schema specification to an executable' ) do
80
+ @options[:compile] = true
81
+ end
82
+
83
+ opts.on( '-s', '--schema SPEC_FILE', 'Schema specification file (required)' ) do |file|
84
+ if @options[:compile]
85
+ @mapping_schema = file
86
+ else
87
+ self.mapping_schema = file
88
+ end
89
+ end
90
+ end
91
+
92
+ @options[:output_dir] ||= '.'
93
+ opts.on( '-o', '--output DIR', "Output directory (default: #{@options[:output_dir]})" ) do |dir|
94
+ abort "Output directory #{dir} doesn't exist" unless compile? or Dir.exist?(dir)
39
95
  @options[:output_dir] = dir
40
96
  end
41
97
 
42
- @options[:output_format] = 'ttl'
98
+ @options[:output_format] ||= 'ttl'
43
99
  opts.on( '-f', '--output-format FORMAT', 'Serialization format for the RDF data',
44
- "FORMAT being one of: nt, n3, ttl, rdf, xml, html, json (default: ttl)") do |format|
45
- #format = 'turtle' if format == 'ttl'
100
+ "FORMAT being one of: nt, n3, ttl, rdf, xml, html, json (default: #{@options[:output_format]})") do |format|
46
101
  @options[:output_format] = format.strip.downcase
47
102
  end
48
103
 
49
- @options[:schema_spec_file] = nil
50
- opts.on( '-s', '--schema SPEC_FILE', 'Schema specification file (required)' ) do |file|
51
- @options[:schema_spec_file] = file
104
+ opts.on( '-d', '--debug', 'Run in debug mode' ) do
105
+ Spread2RDF.debug_mode = true
52
106
  end
53
107
 
54
108
  end
55
-
56
109
  optparse.parse!
57
- raise OptionParser::ParseError, 'required file arguments missing' if ARGV.empty?
58
- raise OptionParser::ParseError, 'required schema specification file missing' if @options[:schema_spec_file].nil?
59
-
60
- @input_file = ARGV.first
110
+ if compile?
111
+ @mapping_schema ||= ARGV.first or raise OptionParser::ParseError, 'required schema specification file missing'
112
+ else
113
+ raise OptionParser::ParseError, 'required schema specification file missing' if @mapping_schema.nil?
114
+ @input_file = ARGV.first or @input_file or
115
+ raise OptionParser::ParseError, 'required file arguments missing'
116
+ end
61
117
  rescue OptionParser::ParseError => e
62
118
  puts e.message
63
119
  puts optparse.help
@@ -72,8 +128,8 @@ module Spread2RDF
72
128
 
73
129
  def write_output
74
130
  filename = output_filename
75
- abort 'No RDF data to write!' if @table.try(:to_rdf).blank?
76
- graph = @table.to_rdf
131
+ abort 'No RDF data to write!' if @mapping.try(:graph).blank?
132
+ graph = @mapping.graph
77
133
  puts "Writing #{graph.count} RDF statements to #{filename} ... "
78
134
  # TODO: base_uri: ... for writer constructor
79
135
  RDF::Writer.open(filename) do |writer|
@@ -85,7 +141,45 @@ module Spread2RDF
85
141
  end
86
142
  graph.each_statement { |statement| writer << statement }
87
143
  end
144
+
145
+ end
146
+
147
+ def convert
148
+ puts "Reading #{@input_file} ..."
149
+ @mapping = mapping_schema.map(@input_file)
150
+ write_output
151
+ end
152
+
153
+ def compile(mapping_file)
154
+ output = if File.directory?(@options[:output_dir])
155
+ output_dir = @options[:output_dir]
156
+ output_file = File.basename(mapping_file, File.extname(mapping_file)) + '.exe'
157
+ File.join(output_dir, output_file)
158
+ else
159
+ @options[:output_dir] += '.exe' unless File.extname(@options[:output_dir]) == '.exe'
160
+ @options[:output_dir]
161
+ end
162
+ ocra_options = [
163
+ '--gem-full',
164
+ '--add-all-core',
165
+ '--no-autoload',
166
+ '--no-dep-run',
167
+ '--no-enc',
168
+ '--console'
169
+ ]
170
+ #ocra_options << '--quiet' unless Spread2RDF.debug_mode
171
+ ocra_options << '--debug' if Spread2RDF.debug_mode
172
+ ocra_gemfile = File.join(Spread2RDF::ROOT, 'Gemfile.ocra')
173
+ ocra_options << "--gemfile #{ocra_gemfile}"
174
+ ocra_options << "--output #{output}"
175
+ ocra_cmd = "ocra #{ocra_options.join(' ')} #{mapping_file}"
176
+ puts "compiling #{mapping_file} to #{output}"
177
+ #puts ocra_cmd
178
+ Kernel.system(ocra_cmd)
88
179
  end
180
+
89
181
  self
90
182
  end
91
- end
183
+
184
+ CLI = Cli.instance
185
+ end
@@ -0,0 +1,49 @@
1
+ module Spread2RDF
2
+ class Coord < Struct.new(:column, :row)
3
+ def initialize(*args)
4
+ case args.length
5
+ when 2 then super
6
+ when 1
7
+ case args = args.first
8
+ when Hash
9
+ super(args[:column], args[:row])
10
+ when Symbol, String
11
+ coord = args.to_s
12
+ raise "Invalid cell coordinates #{coord}" unless coord =~ /(\w+)(\d+)/
13
+ super(Regexp.last_match[1], Regexp.last_match[2].to_i)
14
+ else raise ArgumentError, "can't handle argument #{args}"
15
+ end
16
+ else raise ArgumentError, "too many arguments: #{args}"
17
+ end
18
+ end
19
+
20
+ def column_as_number
21
+ Roo::Base.letter_to_number(column)
22
+ end
23
+
24
+ def column_as_index
25
+ column_as_number - 1
26
+ end
27
+
28
+ def increment_column(count = 1)
29
+ self.class.increment_column(self.column, count)
30
+ end
31
+
32
+ def to_s
33
+ "#{column}#{row}"
34
+ end
35
+
36
+ def to_sym
37
+ to_s.to_sym
38
+ end
39
+
40
+ class << self
41
+ alias [] new
42
+
43
+ def increment_column(column, count=1)
44
+ Roo::Base.number_to_letter(Roo::Base.letter_to_number(column) + count)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,105 @@
1
+ module Spread2RDF
2
+ module Mapping
3
+ class Cell < Element
4
+
5
+ attr_reader :row
6
+
7
+ def_delegators :parent, :subject, :worksheet, :resource
8
+ def_delegators :schema, :predicate
9
+
10
+ def initialize(sheet, parent, row)
11
+ super(sheet, parent)
12
+ @row = row
13
+ map
14
+ end
15
+
16
+ def map
17
+ exec(&schema.block) unless empty?
18
+ end
19
+
20
+ def coord
21
+ Coord[column: schema.coord, row: row]
22
+ end
23
+
24
+ def value
25
+ @value ||= worksheet.cell_value(coord)
26
+ end
27
+
28
+ def object
29
+ @object ||= value && map_to_object(value)
30
+ end
31
+
32
+ def empty?
33
+ value.blank?
34
+ end
35
+
36
+ def map_to_object(value)
37
+ case schema.object_mapping_mode
38
+ when :to_string then value
39
+ when :resource_ref then resolve_resource_ref
40
+ when :new_resource then create_resource_object
41
+ when :custom then exec(&schema.cell_mapping)
42
+ else raise 'internal error: unknown column mapping type'
43
+ end
44
+ end
45
+ private :map_to_object
46
+
47
+ def resolve_resource_ref
48
+ source = schema.object[:from]
49
+ source = { worksheet: source } if source.is_a? Symbol
50
+ raise ArgumentError, "expecting a Hash as source, but got #{source}" unless source.is_a? Hash
51
+ source_worksheet = source[:worksheet]
52
+ source_worksheet = spreadsheet.worksheet(source_worksheet)
53
+ raise "#{self}: couldn't find source worksheet #{source[:worksheet]}" if source_worksheet.nil?
54
+ source_predicate = source[:predicate] || RDF::RDFS.label
55
+ result = source_worksheet.graph.query([nil, source_predicate, value])
56
+ raise "#{self}: couldn't find a resource for #{value} in #{source_worksheet}" if result.empty?
57
+ raise "#{self}: found multiple resources for #{value} in #{source_worksheet}: #{result.map(&:subject)}" if result.count > 1
58
+ result.first.subject
59
+ end
60
+ private :resolve_resource_ref
61
+
62
+ def create_resource_object
63
+ case
64
+ when (schema.object.try(:fetch, :uri, nil) || object) == :bnode
65
+ RDF::Node.new
66
+ else
67
+ raise NotImplementedError
68
+ end
69
+ end
70
+ private :create_resource_object
71
+
72
+ ##########################################################################
73
+ # for the DSL for column statement blocks
74
+
75
+ def value_of_column(name)
76
+ sheet_schema = parent.parent.schema
77
+ other_column = sheet_schema.column(name)
78
+ raise "couldn't find column #{name} when mapping #{self}" if
79
+ other_column.nil?
80
+ worksheet.cell_value(column: other_column.coord, row: row)
81
+ end
82
+
83
+ def object_of_column(name)
84
+ other_column = resource.column!(name)
85
+ raise "couldn't find column #{name} when mapping #{self}" if
86
+ other_column.nil?
87
+ other_column.cell!(row).object
88
+ end
89
+
90
+ def exec(&block)
91
+ #puts "executing block of #{@___column___} in row #{row}"
92
+ self.instance_exec(value, &block) if block_given?
93
+ end
94
+ private :exec
95
+
96
+ ##########################################################################
97
+ # Element#_children_
98
+
99
+ def _children_
100
+ nil
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,63 @@
1
+ module Spread2RDF
2
+ module Mapping
3
+ class Column < Element
4
+ include Statement
5
+
6
+ def_delegators :parent, :subject, :worksheet, :row_range
7
+ def_delegators :schema, :predicate
8
+
9
+ alias resource parent
10
+
11
+ def initialize(sheet, parent)
12
+ super
13
+ @cells = {}
14
+ map(row_range)
15
+ end
16
+
17
+ def map(range)
18
+ #puts "mapping #{self} in #{range} ..."
19
+ case range
20
+ when Integer
21
+ cell = cell!(range)
22
+ statements_to_object(cell.object) unless cell.empty?
23
+ when Range
24
+ range.each { |row| self.map(row) }
25
+ else raise ArgumentError
26
+ end
27
+ end
28
+
29
+ def objects
30
+ cells.map(&:object)
31
+ end
32
+
33
+ def cell_coord(row)
34
+ case row
35
+ when Integer then Coord[column: schema.coord, row: row]
36
+ when Coord then Coord
37
+ when Hash then Coord[row]
38
+ else raise ArgumentError
39
+ end
40
+ end
41
+
42
+ ##########################################################################
43
+ # Mapping::Element structure
44
+
45
+ def cells
46
+ @cells.values
47
+ end
48
+ alias _children_ cells
49
+
50
+ def cell(coord)
51
+ coord = cell_coord(coord)
52
+ @cells[coord.to_sym] # TODO: search @sub_sheet_mappings also
53
+ end
54
+
55
+ def cell!(coord)
56
+ coord = cell_coord(coord)
57
+ @cells[coord.to_sym] ||= Cell.new(schema, self, coord.row)
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,23 @@
1
+ module Spread2RDF
2
+ module Mapping
3
+ class ColumnBlock < Sheet
4
+ include Statement
5
+
6
+ def_delegators :parent, :subject, :row_range
7
+ def_delegators :schema, :predicate
8
+
9
+ def map
10
+ super
11
+ @resources.each do |resource|
12
+ statements_to_object(resource.subject) unless resource.empty?
13
+ end
14
+ self
15
+ end
16
+
17
+ def objects
18
+ @resources.map(&:subject)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ module Spread2RDF
2
+ module Mapping
3
+ class Cell
4
+ module Default
5
+ def self.unit_mapping(value)
6
+ @qudt ||= RDF::Graph.load File.join(ONTOLOGY_DIR, 'unit-v1.1.ttl')
7
+ query = RDF::Query.new(
8
+ unit: { RDF::URI.new('http://qudt.org/schema/qudt#symbol') =>
9
+ RDF::Literal.new(value, datatype: RDF::XSD.string) })
10
+ solutions = query.execute(@qudt)
11
+ raise "unit #{value} is not unique; possible candidates:
12
+ #{solutions.map(&:unit).ai}" if solutions.count > 1
13
+ raise "couldn't find a QUDT unit for unit '#{value}''" if solutions.empty?
14
+ solutions.first.unit
15
+ end
16
+
17
+ def self.uri_normalization(string)
18
+ string
19
+ .gsub(', ', '-')
20
+ .gsub(' ', '-')
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,64 @@
1
+ require 'forwardable'
2
+
3
+ module Spread2RDF
4
+ module Mapping
5
+ class Element
6
+ extend Forwardable
7
+
8
+ attr_reader :schema
9
+ attr_reader :parent
10
+
11
+ def_delegators :parent, :spreadsheet
12
+
13
+ def initialize(schema, parent)
14
+ @graph = RDF::Repository.new
15
+ @schema = schema
16
+ @parent = parent
17
+ end
18
+
19
+ def to_s
20
+ "#{self.class.name.split('::').last}-mapping of #{schema}"
21
+ end
22
+
23
+ ##########################################################################
24
+ # children
25
+
26
+ def _children_
27
+ raise NotImplementedError, 'subclasses must implement this method'
28
+ end
29
+
30
+ def empty?
31
+ _children_.empty? or _children_.all?(&:empty?)
32
+ end
33
+
34
+ ##########################################################################
35
+ # RDF graph
36
+
37
+ def graph
38
+ if _children_
39
+ _children_.inject(@graph.clone) { |graph, child| graph << child.graph }
40
+ else
41
+ @graph
42
+ end
43
+ end
44
+ alias to_rdf graph
45
+
46
+ private
47
+
48
+ def add_statement(*args)
49
+ args = args.first if args.count == 1 and args.first.is_a? Array
50
+ #puts "adding statement: #{args.inspect}"
51
+ raise "internal error: trying to add a bad triple with nil value: #{args}" if args.count != 3 or args.one? { |arg| arg.nil? }
52
+ @graph << RDF::Statement.new(*args)
53
+ end
54
+ alias statement add_statement
55
+
56
+ def add_statements(*args)
57
+ args = args.first if args.count == 1 and args.first.is_a? Array
58
+ args.each { |arg| statement(arg) }
59
+ end
60
+ alias statements add_statements
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,95 @@
1
+ module Spread2RDF
2
+ module Mapping
3
+ class Resource < Element
4
+
5
+ attr_reader :row_range
6
+
7
+ def_delegators :parent, :worksheet
8
+
9
+ def initialize(sheet, parent, row_range)
10
+ super(sheet, parent)
11
+ @columns = {}
12
+ @row_range = row_range
13
+ map
14
+ end
15
+
16
+ def map
17
+ #puts "processing #{self} in #{row_range}"
18
+ object_columns = parent.schema.columns - [parent.schema.subject_column]
19
+ object_columns.each { |column| column!(column) }
20
+ subject_description unless empty?
21
+ self
22
+ end
23
+
24
+ ##########################################################################
25
+ # subject mapping
26
+
27
+ def subject
28
+ @subject ||=
29
+ case schema.subject_mapping_mode
30
+ when :bnode then RDF::Node.new
31
+ when :from_column then subject_resource_from_column
32
+ else raise 'unknown subject mapping type'
33
+ end
34
+ end
35
+ alias subject_resource subject
36
+
37
+ def subject_name_suffix
38
+ cells = row_range.map do |row|
39
+ parent.cell_value(row: row, column: schema.subject_column.coord).presence
40
+ end.compact
41
+ raise "no subject found for Resource in #{row_range} of #{sheet}" if cells.empty?
42
+ raise "multiple subjects found for Resource in #{row_range} of #{sheet}: #{cells.inspect}" if cells.count > 1
43
+ cells.first
44
+ end
45
+ private :subject_name_suffix
46
+
47
+ def subject_resource_from_column
48
+ namespace = schema.subject_namespace
49
+ subject_suffix = Mapping::Cell::Default.uri_normalization(subject_name_suffix)
50
+ #puts "subject resource for #{sheet} in #{range}: " + RDF::URI.new("#{namespace}#{subject_suffix}" )
51
+ RDF::URI.new("#{namespace}#{subject_suffix}")
52
+ end
53
+ private :subject_resource_from_column
54
+
55
+ def subject_description
56
+ type = schema.subject_resource_type
57
+ statement(subject, RDF.type, type) unless type.nil?
58
+ if type == RDF::RDFS.Class &&
59
+ super_class = schema.subject.try(:fetch, :sub_class_of, nil)
60
+ statement(subject, RDF::RDFS.subClassOf, super_class)
61
+ end
62
+ end
63
+ private :subject_description
64
+
65
+ ##########################################################################
66
+ # Mapping::Element structure
67
+
68
+ def columns
69
+ @columns.values
70
+ end
71
+ alias _children_ columns
72
+
73
+ def column(name)
74
+ @columns[column_schema(name).name]
75
+ end
76
+
77
+ def column!(name)
78
+ column_schema = column_schema(name)
79
+ @columns[column_schema.name] ||= case column_schema
80
+ when Schema::Column then Column.new(column_schema, self)
81
+ when Schema::ColumnBlock then ColumnBlock.new(column_schema, self).map
82
+ end
83
+ end
84
+
85
+ def column_schema(name)
86
+ case name
87
+ when Schema::Column, Schema::ColumnBlock then name
88
+ when String, Symbol then schema.column(name)
89
+ else raise ArgumentError
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end