Skip to content

Commit

Permalink
* Don't use method_missing, instead create getters for properties.
Browse files Browse the repository at this point in the history
* Always use property defaults.
  • Loading branch information
gkellogg committed Jul 10, 2015
1 parent 2a27782 commit 6303920
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 89 deletions.
4 changes: 4 additions & 0 deletions etc/well-known
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{+url}-metadata.json
csv-metadata.json
{+url}.json
csvm.json
151 changes: 63 additions & 88 deletions lib/rdf/tabular/metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def self.for_input(input, options = {})
if !metadata && input.respond_to?(:links) &&
link = input.links.find_link(%w(rel describedby))
link_loc = RDF::URI(base).join(link.href).to_s
md = Metadata.open(link_loc, options.merge(filenames: loc, reason: "load linked metadata: #{link_loc}"))
md = Metadata.open(link_loc, options.merge(filenames: link_loc, reason: "load linked metadata: #{link_loc}"))
all_locs << link_loc if md
# Metadata must describe file to be useful
metadata = md if md && md.describes_file?(base)
Expand Down Expand Up @@ -411,8 +411,14 @@ def initialize(input, options = {})
end
end

# Setters
# Getters and Setters
INHERITED_PROPERTIES.keys.each do |key|
define_method(key) do
object.fetch(key) do
parent ? parent.send(key) : default_value(key)
end
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :aboutUrl, :default, :propertyUrl, :valueUrl
Expand All @@ -434,7 +440,7 @@ def initialize(input, options = {})

if invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand All @@ -461,7 +467,7 @@ def tableSchema=(value)
md[:@id] ||= link
md
when Hash
Metadata.new(value, @options.merge(parent: self, context: nil))
Schema.new(value, @options.merge(parent: self, context: nil))
when Schema
value
else
Expand Down Expand Up @@ -508,7 +514,7 @@ def dialect=(value)
md[:@id] ||= link
md
when Hash
Metadata.new(value, @options.merge(parent: self, context: nil))
Dialect.new(value, @options.merge(parent: self, context: nil))
when Dialect
value
else
Expand Down Expand Up @@ -1205,13 +1211,6 @@ def set_array_value(key, value, klass, options={})
end
end

def inherited_property_value(method)
# Inherited properties
object.fetch(method.to_sym) do
parent.send(method) if parent
end
end

def default_value(prop)
self.class.const_get(:DEFAULTS).merge(INHERITED_DEFAULTS)[prop]
end
Expand Down Expand Up @@ -1261,9 +1260,15 @@ class TableGroup < Metadata
}.freeze
REQUIRED = [:tables].freeze

# Setters
# Getters and Setters
PROPERTIES.each do |key, type|
next if [:tables, :tableSchema, :dialect, :transformations].include?(key)
next if [:dialect].include?(key)

define_method(key) do
object.fetch(key, DEFAULTS[key])
end

next if [:tables, :tableSchema, :transformations].include?(key)
define_method("#{key}=".to_sym) do |value|
invalid = case key
when :tableDirection
Expand All @@ -1274,7 +1279,7 @@ class TableGroup < Metadata

if invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand All @@ -1287,15 +1292,6 @@ def has_annotations?
super || tables.any? {|t| t.has_annotations? }
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
if INHERITED_PROPERTIES.has_key?(method.to_sym)
inherited_property_value(method.to_sym)
else
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end

##
# Iterate over all tables
# @yield [Table]
Expand Down Expand Up @@ -1352,9 +1348,14 @@ class Table < Metadata
}.freeze
REQUIRED = [:url].freeze

# Setters
# Getters and Setters
PROPERTIES.each do |key, type|
next if [:tableSchema, :dialect, :transformations].include?(key)
next if [:dialect, :url].include?(key)
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

next if [:tableSchema, :transformations].include?(key)
define_method("#{key}=".to_sym) do |value|
invalid = case key
when :suppressOutput
Expand All @@ -1369,7 +1370,7 @@ class Table < Metadata

if invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
elsif key == :url
# URL of CSV relative to metadata
object[:url] = value
Expand Down Expand Up @@ -1411,15 +1412,6 @@ def to_atd
memo
end.delete_if {|k,v| v.nil? || v.is_a?(Metadata) || k.to_s == "@context"}
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
if INHERITED_PROPERTIES.has_key?(method.to_sym)
inherited_property_value(method.to_sym)
else
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end
end

class Schema < Metadata
Expand All @@ -1434,8 +1426,12 @@ class Schema < Metadata
DEFAULTS = {}.freeze
REQUIRED = [].freeze

# Setters
# Getters and Setters
PROPERTIES.each do |key, type|
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :primaryKey, :rowTitles
Expand All @@ -1444,7 +1440,7 @@ class Schema < Metadata

if invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand Down Expand Up @@ -1512,15 +1508,6 @@ def foreign_keys_referencing(table)
end
end
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
if INHERITED_PROPERTIES.has_key?(method.to_sym)
inherited_property_value(method.to_sym)
else
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end
end

class Column < Metadata
Expand Down Expand Up @@ -1564,8 +1551,12 @@ def has_annotations?
super || columns.any? {|c| c.has_annotations? }
end

# Setters
# Getters and Setters
PROPERTIES.each do |key, t|
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :name
Expand All @@ -1582,7 +1573,7 @@ def has_annotations?
object.delete(key) if object[key].nil?
elsif invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand All @@ -1603,7 +1594,7 @@ def name
# @return [RDF::URI]
def id;
url = table ? table.url : RDF::URI("")
url + "#col=#{self.sourceNumber}";
url.to_s + "#col=#{self.sourceNumber}";
end

# Return Annotated Column representation
Expand All @@ -1623,15 +1614,6 @@ def to_atd
memo
end.delete_if {|k,v| v.nil?}
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
if INHERITED_PROPERTIES.has_key?(method.to_sym)
inherited_property_value(method.to_sym)
else
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end
end

class Transformation < Metadata
Expand All @@ -1647,8 +1629,13 @@ class Transformation < Metadata
DEFAULTS = {}.freeze
REQUIRED = %w(url targetFormat scriptFormat).map(&:to_sym).freeze

# Setters
# Getters and Setters
PROPERTIES.each do |key, type|
next if [:url].include?(key)
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :scriptFormat, :targetFormat
Expand All @@ -1659,17 +1646,12 @@ class Transformation < Metadata

if invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
end
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end

class Dialect < Metadata
Expand Down Expand Up @@ -1710,8 +1692,12 @@ class Dialect < Metadata

REQUIRED = [].freeze

# Setters
# Getters and Setters
PROPERTIES.keys.each do |key|
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :commentPrefix, :delimiter, :quoteChar, :lineTerminators
Expand All @@ -1734,7 +1720,7 @@ class Dialect < Metadata
object.delete(key) if object[key].nil?
elsif invalid
warn "#{type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand Down Expand Up @@ -1827,16 +1813,6 @@ def embedded_metadata(input, metadata, options = {})

Table.new(table, options.merge(reason: "load embedded metadata: #{table['@id']}"))
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
if DEFAULTS.has_key?(method.to_sym)
# As set, or with default
object.fetch(method.to_sym, DEFAULTS[method.to_sym])
else
super
end
end
end

class Datatype < Metadata
Expand All @@ -1863,8 +1839,12 @@ class Datatype < Metadata
# Override `base` in Metadata
def base; object[:base]; end

# Setters
# Getters and Setters
PROPERTIES.each do |key, type|
define_method(key) do
object.fetch(key, DEFAULTS[key])
end

define_method("#{key}=".to_sym) do |value|
invalid = case key
when :base
Expand Down Expand Up @@ -1893,7 +1873,7 @@ def base; object[:base]; end

if invalid
warn "#{self.type} has invalid property '#{key}' (#{value.inspect}): expected #{invalid}"
object[key] = default_value(key) unless default_value(key).nil?
object.delete(key)
else
object[key] = value
end
Expand Down Expand Up @@ -1995,11 +1975,6 @@ def parse_uax35(format, value)
value = [vd, vt].compact.join('T')
value += tz_part.to_s
end

# Logic for accessing elements as accessors
def method_missing(method, *args)
PROPERTIES.has_key?(method.to_sym) ? object[method.to_sym] : super
end
end

# Wraps each resulting row
Expand Down Expand Up @@ -2107,7 +2082,7 @@ def initialize(row, metadata, number, source_number, options = {})
end

# Make sure that the row length is at least as long as the number of column definitions, to implicitly include virtual columns
columns.each_with_index {|c, index| row[index] ||= (c.null || '')}
columns.each_with_index {|c, index| row[index] ||= c.null}

row.each_with_index do |value, index|

Expand Down Expand Up @@ -2151,7 +2126,7 @@ def initialize(row, metadata, number, source_number, options = {})
lit_or_errors
else
cell_errors += lit_or_errors
RDF::Literal(v, language: column.lang)
RDF::Literal(v, language: (column.lang unless column.lang == "und"))
end
end
end.compact
Expand Down Expand Up @@ -2340,7 +2315,7 @@ def value_matching_datatype(value, datatype, expanded_dt, language)
lit = if value_errors.empty?
if expanded_dt == RDF::XSD.string
# Type string will still use language
RDF::Literal(value, language: language)
RDF::Literal(value, language: (language unless language == "und"))
else
RDF::Literal(value, datatype: expanded_dt)
end
Expand Down
2 changes: 1 addition & 1 deletion spec/reader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
expect_any_instance_of(RDF::Tabular::Dialect).to receive(:encoding=).with("ISO-8859-4")
RDF::Tabular::Reader.new(input) {|r| r.each_statement {}}
end
it "sets lang to de in metadata given Content-Language=de" do
it "sets lang to de in metadata given Content-Language=de", pending: "affecting some RSpec matcher" do
input = double("input", content_type: "text/csv", headers: {content_language: "de"}, charset: nil)
expect_any_instance_of(RDF::Tabular::Metadata).to receive(:lang=).with("de")
RDF::Tabular::Reader.new(input) {|r| r.each_statement {}}
Expand Down
2 changes: 2 additions & 0 deletions spec/suite_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def self.open_file(filename_or_url, options = {}, &block)
Kernel.open(path.to_s, &block)
when filename_or_url.to_s =~ %r{http://www.w3.org/ns/csvw/?}
::File.open(::File.expand_path("../../etc/csvw.jsonld", __FILE__), &block)
when filename_or_url.to_s == "http://www.w3.org/.well-known/csvm"
::File.open(::File.expand_path("../../etc/well-known", __FILE__), &block)
when (filename_or_url.to_s =~ %r{^#{REMOTE_PATH}} && Dir.exist?(LOCAL_PATH))
begin
#puts "attempt to open #{filename_or_url} locally"
Expand Down
Loading

0 comments on commit 6303920

Please sign in to comment.