atdis 0.3.13 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +46 -0
  3. data/.ruby-version +1 -1
  4. data/Gemfile +9 -7
  5. data/Guardfile +4 -3
  6. data/Rakefile +4 -2
  7. data/atdis.gemspec +10 -5
  8. data/lib/atdis.rb +2 -0
  9. data/lib/atdis/feed.rb +31 -24
  10. data/lib/atdis/model.rb +101 -99
  11. data/lib/atdis/models/address.rb +10 -4
  12. data/lib/atdis/models/application.rb +12 -9
  13. data/lib/atdis/models/authority.rb +11 -6
  14. data/lib/atdis/models/document.rb +8 -6
  15. data/lib/atdis/models/event.rb +10 -8
  16. data/lib/atdis/models/info.rb +73 -49
  17. data/lib/atdis/models/land_title_ref.rb +15 -7
  18. data/lib/atdis/models/location.rb +9 -7
  19. data/lib/atdis/models/page.rb +34 -19
  20. data/lib/atdis/models/pagination.rb +91 -32
  21. data/lib/atdis/models/person.rb +7 -5
  22. data/lib/atdis/models/reference.rb +7 -5
  23. data/lib/atdis/models/response.rb +5 -3
  24. data/lib/atdis/models/torrens_title.rb +9 -7
  25. data/lib/atdis/separated_url.rb +17 -15
  26. data/lib/atdis/validators.rb +46 -39
  27. data/lib/atdis/version.rb +3 -1
  28. data/spec/atdis/feed_spec.rb +126 -34
  29. data/spec/atdis/model_spec.rb +124 -51
  30. data/spec/atdis/models/address_spec.rb +18 -9
  31. data/spec/atdis/models/application_spec.rb +222 -155
  32. data/spec/atdis/models/authority_spec.rb +45 -15
  33. data/spec/atdis/models/document_spec.rb +10 -4
  34. data/spec/atdis/models/event_spec.rb +23 -11
  35. data/spec/atdis/models/info_spec.rb +191 -116
  36. data/spec/atdis/models/land_title_ref_spec.rb +32 -16
  37. data/spec/atdis/models/location_spec.rb +75 -60
  38. data/spec/atdis/models/page_spec.rb +241 -135
  39. data/spec/atdis/models/pagination_spec.rb +177 -77
  40. data/spec/atdis/models/person_spec.rb +8 -4
  41. data/spec/atdis/models/reference_spec.rb +29 -16
  42. data/spec/atdis/models/response_spec.rb +2 -1
  43. data/spec/atdis/models/torrens_title_spec.rb +24 -18
  44. data/spec/atdis/separated_url_spec.rb +14 -15
  45. data/spec/spec_helper.rb +14 -10
  46. metadata +56 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 115d598c77fb6437ed05614cadc31664786185e4
4
- data.tar.gz: 30ac0686681de9748e37171f360d63e72786126d
3
+ metadata.gz: 0c42c8984e3515ca6f1a98e02e774cfbf30b28e9
4
+ data.tar.gz: e3fd6b0fa426195259d1b392dda98f55d5f9c9b7
5
5
  SHA512:
6
- metadata.gz: 502e18e86ed22d0fb1b34130902716ba4c8c020cc1ed1bda8ac8b7c91dc539512a8dbf6cfa49cbe6910b85df6a88cdc0909d1b1f0b35eca2f33f257e359952a9
7
- data.tar.gz: f30ae1357c7c3f9db5188a1703822b759c805fe9d929443a1751395ed58dccad946e083f06bd7419eea4e733af3faff73cdf15ce463c2b4aa12727a46c00c070
6
+ metadata.gz: 6ebeaa70b6b9eb739cd47aa8c8b9bec5b8d15b71efb99b6263c1327cab6a2b84866a2b304959d65542b9a1a94580b55445bd417f8fe302ae2708c2c45d5d27f6
7
+ data.tar.gz: 4d72b3a0621f1d40fbaf0cf517cf35b7f1d17817422ede3273d22d0f5de2ec008456612337131b649916b45872fe3afb0b97970eae2e72a9870ed17b86fb3b6f
data/.rubocop.yml ADDED
@@ -0,0 +1,46 @@
1
+ # Bumping max line length to something a little more reasonable
2
+ Metrics/LineLength:
3
+ Max: 100
4
+
5
+ # Not so worried about top-level class documentation. So...
6
+ Style/Documentation:
7
+ Enabled: false
8
+
9
+ # We prefer double quotes here and it we're making liberal use of multi-line
10
+ # strings so it makes sense to enforce those to be consistent oo
11
+ Style/StringLiterals:
12
+ EnforcedStyle: double_quotes
13
+ ConsistentQuotesInMultiline: true
14
+
15
+ # This one I disagree with. Putting seperators in large numbers makes sense
16
+ # in some circumstances but in others (an example id in a database table)
17
+ # it's just nonsensical. Also, I think this one might also be a bit US centric.
18
+ Style/NumericLiterals:
19
+ Enabled: false
20
+
21
+ # Disable a bunch of metrics to do with code complexity. These as are all
22
+ # a bit hard-nosed. Maybe after we've done a pass with Code Climate we
23
+ # can revisit these
24
+ Metrics/AbcSize:
25
+ Enabled: false
26
+
27
+ Metrics/BlockLength:
28
+ Enabled: false
29
+
30
+ Metrics/ClassLength:
31
+ Enabled: false
32
+
33
+ Metrics/CyclomaticComplexity:
34
+ Enabled: false
35
+
36
+ Metrics/MethodLength:
37
+ Enabled: false
38
+
39
+ Metrics/ModuleLength:
40
+ Enabled: false
41
+
42
+ Metrics/ParameterLists:
43
+ Enabled: false
44
+
45
+ Metrics/PerceivedComplexity:
46
+ Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.0.0-p353
1
+ ruby-2.3.1
data/Gemfile CHANGED
@@ -1,14 +1,16 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  group :development do
6
+ gem "coveralls", require: false
7
+ gem "growl"
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "rb-fsevent", "~> 0.9"
4
11
  gem "rspec"
5
- gem 'guard'
6
- gem 'guard-rspec'
7
- gem 'growl'
8
- gem 'rb-fsevent', '~> 0.9'
9
12
  # Probably required on OS X. See https://github.com/guard/guard/wiki/Add-Readline-support-to-Ruby-on-Mac-OS-X
10
- gem 'rb-readline'
11
- gem 'coveralls', require: false
13
+ gem "rb-readline"
12
14
  end
13
15
 
14
16
  # Specify your gem's dependencies in atdis.gemspec
data/Guardfile CHANGED
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # More info at https://github.com/guard/guard#readme
2
4
 
3
- guard 'rspec' do
4
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ guard "rspec" do
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
7
  watch(%r{^spec/.+_spec\.rb$})
6
8
  end
7
-
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
 
3
- require 'rspec/core/rake_task'
5
+ require "rspec/core/rake_task"
4
6
 
5
- RSpec::Core::RakeTask.new('spec')
7
+ RSpec::Core::RakeTask.new("spec")
6
8
 
7
9
  # If you want to make this the default task
8
10
  task default: :spec
data/atdis.gemspec CHANGED
@@ -1,14 +1,16 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'atdis/version'
5
+ require "atdis/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
7
8
  spec.name = "atdis"
8
9
  spec.version = Atdis::VERSION
9
10
  spec.authors = ["Matthew Landauer"]
10
11
  spec.email = ["matthew@openaustraliafoundation.org.au"]
11
- spec.description = %q{A ruby interface to the application tracking data interchange specification (ATDIS) API}
12
+ spec.description =
13
+ "A ruby interface to the application tracking data interchange specification (ATDIS) API"
12
14
  spec.summary = spec.description
13
15
  spec.homepage = "http://github.com/openaustralia/atdis"
14
16
  spec.license = "MIT"
@@ -17,12 +19,15 @@ Gem::Specification.new do |spec|
17
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
21
  spec.require_paths = ["lib"]
22
+ spec.required_ruby_version = ">= 2.3.1"
20
23
 
21
24
  spec.add_development_dependency "bundler", "~> 1.3"
22
25
  spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rubocop"
23
27
 
28
+ spec.add_dependency "activemodel"
29
+ spec.add_dependency "activesupport"
24
30
  spec.add_dependency "multi_json", "~> 1.7"
25
31
  spec.add_dependency "rest-client"
26
32
  spec.add_dependency "rgeo-geojson"
27
- spec.add_dependency "activemodel"
28
33
  end
data/lib/atdis.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "atdis/version"
2
4
 
3
5
  require "atdis/validators"
data/lib/atdis/feed.rb CHANGED
@@ -1,23 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rest-client"
2
4
 
3
5
  module ATDIS
4
6
  class Feed
5
- attr_reader :base_url
7
+ attr_reader :base_url, :timezone
6
8
 
7
- VALID_OPTIONS = [:page, :street, :suburb, :postcode, :lodgement_date_start, :lodgement_date_end, :last_modified_date_start, :last_modified_date_end]
9
+ VALID_OPTIONS = %i[page street suburb postcode lodgement_date_start
10
+ lodgement_date_end last_modified_date_start last_modified_date_end].freeze
8
11
 
9
12
  # base_url - the base url from which the urls for all atdis urls are made
10
13
  # It should be of the form:
11
14
  # http://www.council.nsw.gov.au/atdis/1.0
12
- def initialize(base_url)
15
+ # timezone - a string (e.g. "Sydney") for the timezone in which times are returned
16
+ # (Note: times in the feeds that have timezones specified get converted to the
17
+ # timezone given while times in the feed which don't have a timezone specified
18
+ # get interpreted in the given timezone)
19
+ # See https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html for the
20
+ # list of possible timezone strings
21
+ def initialize(base_url, timezone)
13
22
  @base_url = base_url
23
+ @timezone = timezone
14
24
  end
15
25
 
16
26
  def applications_url(options = {})
17
27
  invalid_options = options.keys - VALID_OPTIONS
18
- if !invalid_options.empty?
19
- raise "Unexpected options used: #{invalid_options.join(',')}"
20
- end
28
+
29
+ raise "Unexpected options used: #{invalid_options.join(',')}" unless invalid_options.empty?
30
+
21
31
  options[:street] = options[:street].join(",") if options[:street].respond_to?(:join)
22
32
  options[:suburb] = options[:suburb].join(",") if options[:suburb].respond_to?(:join)
23
33
  options[:postcode] = options[:postcode].join(",") if options[:postcode].respond_to?(:join)
@@ -27,7 +37,7 @@ module ATDIS
27
37
  end
28
38
 
29
39
  def application_url(id)
30
- "#{base_url}/#{CGI::escape(id)}.json"
40
+ "#{base_url}/#{CGI.escape(id)}.json"
31
41
  end
32
42
 
33
43
  def self.base_url_from_url(url)
@@ -45,44 +55,39 @@ module ATDIS
45
55
  def self.options_from_url(url)
46
56
  u = URI.parse(url)
47
57
  options = query_to_options(u.query)
48
- [:lodgement_date_start, :lodgement_date_end, :last_modified_date_start, :last_modified_date_end].each do |k|
58
+ %i[lodgement_date_start lodgement_date_end last_modified_date_start
59
+ last_modified_date_end].each do |k|
49
60
  options[k] = Date.parse(options[k]) if options[k]
50
61
  end
51
62
  options[:page] = options[:page].to_i if options[:page]
52
63
  # Remove invalid options
53
- options.keys.each do |key|
54
- if !VALID_OPTIONS.include?(key)
55
- options.delete(key)
56
- end
64
+ options.each_key do |key|
65
+ options.delete(key) unless VALID_OPTIONS.include?(key)
57
66
  end
58
67
  options
59
68
  end
60
69
 
61
70
  def applications(options = {})
62
- Models::Page.read_url(applications_url(options))
71
+ Models::Page.read_url(applications_url(options), timezone)
63
72
  end
64
73
 
65
74
  def application(id)
66
- Models::Application.read_url(application_url(id))
75
+ Models::Application.read_url(application_url(id), timezone)
67
76
  end
68
77
 
69
- private
70
-
71
78
  # Turn a query string of the form "foo=bar&hello=sir" to {foo: "bar", hello: sir"}
72
79
  def self.query_to_options(query)
73
80
  options = {}
74
- if query
75
- query.split("&").each do |t|
76
- key, value = t.split("=")
77
- options[key.to_sym] = (CGI::unescape(value) if value)
78
- end
81
+ (query || "").split("&").each do |t|
82
+ key, value = t.split("=")
83
+ options[key.to_sym] = (CGI.unescape(value) if value)
79
84
  end
80
85
  options
81
86
  end
82
87
 
83
88
  # Escape but leave commas unchanged (which are valid in query strings)
84
- def self.escape(v)
85
- CGI::escape(v.to_s).gsub('%2C',',')
89
+ def self.escape(value)
90
+ CGI.escape(value.to_s).gsub("%2C", ",")
86
91
  end
87
92
 
88
93
  # Turn an options hash of the form {foo: "bar", hello: "sir"} into a query
@@ -91,7 +96,9 @@ module ATDIS
91
96
  if options.empty?
92
97
  nil
93
98
  else
94
- options.sort{|a,b| a.first.to_s <=> b.first.to_s}.map{|k,v| "#{k}=#{escape(v)}"}.join("&")
99
+ options.sort { |a, b| a.first.to_s <=> b.first.to_s }
100
+ .map { |k, v| "#{k}=#{escape(v)}" }
101
+ .join("&")
95
102
  end
96
103
  end
97
104
  end
data/lib/atdis/model.rb CHANGED
@@ -1,6 +1,8 @@
1
- require 'multi_json'
2
- require 'active_model'
3
- require 'date'
1
+ # frozen_string_literal: true
2
+
3
+ require "multi_json"
4
+ require "active_model"
5
+ require "date"
4
6
 
5
7
  module ATDIS
6
8
  module TypeCastAttributes
@@ -11,14 +13,14 @@ module ATDIS
11
13
  end
12
14
 
13
15
  module ClassMethods
14
- # of the form {section: Fixnum, address: String}
15
- def set_field_mappings(p)
16
- define_attribute_methods(p.keys.map{|k| k.to_s})
16
+ # of the form {section: Integer, address: String}
17
+ def field_mappings(params)
18
+ define_attribute_methods(params.keys.map(&:to_s))
17
19
  # Convert all values to arrays. Doing this for the sake of tidier notation
18
20
  self.attribute_types = {}
19
- p.each do |k,v|
20
- v = [v] unless v.kind_of?(Array)
21
- self.attribute_types[k] = v
21
+ params.each do |k, v|
22
+ v = [v] unless v.is_a?(Array)
23
+ attribute_types[k] = v
22
24
  end
23
25
  end
24
26
  end
@@ -40,10 +42,10 @@ module ATDIS
40
42
  include Validators
41
43
  include ActiveModel::AttributeMethods
42
44
  include TypeCastAttributes
43
- attribute_method_suffix '_before_type_cast'
44
- attribute_method_suffix '='
45
+ attribute_method_suffix "_before_type_cast"
46
+ attribute_method_suffix "="
45
47
 
46
- attr_reader :attributes, :attributes_before_type_cast
48
+ attr_reader :attributes, :attributes_before_type_cast, :timezone
47
49
  # Stores any part of the json that could not be interpreted. Usually
48
50
  # signals an error if it isn't empty.
49
51
  attr_accessor :json_left_overs, :json_load_error
@@ -54,7 +56,8 @@ module ATDIS
54
56
 
55
57
  # Partition the data into used and unused by returning [used, unused]
56
58
  def self.partition_by_used(data)
57
- used, unused = {}, {}
59
+ used = {}
60
+ unused = {}
58
61
  if data.respond_to?(:each)
59
62
  data.each do |key, value|
60
63
  if attribute_keys.include?(key)
@@ -69,46 +72,47 @@ module ATDIS
69
72
  [used, unused]
70
73
  end
71
74
 
72
- def self.read_url(url)
73
- r = read_json(RestClient.get(url.to_s).to_str)
75
+ def self.read_url(url, timezone)
76
+ r = read_json(RestClient.get(url.to_s).to_str, timezone)
74
77
  r.url = url.to_s
75
78
  r
76
79
  end
77
80
 
78
- def self.read_json(text)
79
- begin
80
- data = MultiJson.load(text, symbolize_keys: true)
81
- interpret(data)
82
- rescue MultiJson::LoadError => e
83
- a = interpret({response: []})
84
- a.json_load_error = e.to_s
85
- a
86
- end
81
+ def self.read_json(text, timezone)
82
+ data = MultiJson.load(text, symbolize_keys: true)
83
+ interpret(data, timezone)
84
+ rescue MultiJson::LoadError => e
85
+ a = interpret({ response: [] }, timezone)
86
+ a.json_load_error = e.to_s
87
+ a
87
88
  end
88
89
 
89
- def self.interpret(*params)
90
- used, unused = partition_by_used(*params)
91
- new(used.merge(json_left_overs: unused))
90
+ def self.interpret(data, timezone)
91
+ used, unused = partition_by_used(data)
92
+ new(used.merge(json_left_overs: unused), timezone)
92
93
  end
93
94
 
94
95
  def json_loaded_correctly!
95
- if json_load_error
96
- errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
97
- end
96
+ return unless json_load_error
97
+
98
+ errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
98
99
  end
99
100
 
100
101
  def json_errors_local
101
102
  r = []
102
103
  # First show special json error
103
- if !errors[:json].empty?
104
- r << [nil, errors[:json]]
105
- end
106
104
  errors.keys.each do |attribute|
105
+ r << [nil, errors[:json]] unless errors[:json].empty?
107
106
  # The :json attribute is special
108
- if attribute != :json
109
- e = errors[attribute]
110
- r << [{attribute => attributes_before_type_cast[attribute.to_s]}, e.map{|m| ErrorMessage["#{attribute} #{m}", m.spec_section]}] unless e.empty?
111
- end
107
+ next if attribute == :json
108
+
109
+ e = errors[attribute]
110
+ next if e.empty?
111
+
112
+ r << [
113
+ { attribute => attributes_before_type_cast[attribute.to_s] },
114
+ e.map { |m| ErrorMessage["#{attribute} #{m}", m.spec_section] }
115
+ ]
112
116
  end
113
117
  r
114
118
  end
@@ -117,12 +121,11 @@ module ATDIS
117
121
  r = []
118
122
  attributes.each do |attribute_as_string, value|
119
123
  attribute = attribute_as_string.to_sym
120
- e = errors[attribute]
121
124
  if value.respond_to?(:json_errors)
122
- r += value.json_errors.map{|a, b| [{attribute => a}, b]}
123
- elsif value.kind_of?(Array)
124
- f = value.find{|v| v.respond_to?(:json_errors) && !v.json_errors.empty?}
125
- r += f.json_errors.map{|a, b| [{attribute => [a]}, b]} if f
125
+ r += value.json_errors.map { |a, b| [{ attribute => a }, b] }
126
+ elsif value.is_a?(Array)
127
+ f = value.find { |v| v.respond_to?(:json_errors) && !v.json_errors.empty? }
128
+ r += f.json_errors.map { |a, b| [{ attribute => [a] }, b] } if f
126
129
  end
127
130
  end
128
131
  r
@@ -133,22 +136,29 @@ module ATDIS
133
136
  end
134
137
 
135
138
  # Have we tried to use this attribute?
136
- def used_attribute?(a)
137
- !attributes_before_type_cast[a].nil?
139
+ def used_attribute?(attribute)
140
+ !attributes_before_type_cast[attribute].nil?
138
141
  end
139
142
 
140
143
  def json_left_overs_is_empty
141
- if json_left_overs && !json_left_overs.empty?
142
- # We have extra parameters that shouldn't be there
143
- errors.add(:json, ErrorMessage["Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}", "4"])
144
- end
144
+ return unless json_left_overs && !json_left_overs.empty?
145
+
146
+ # We have extra parameters that shouldn't be there
147
+ errors.add(
148
+ :json,
149
+ ErrorMessage["Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}", "4"]
150
+ )
145
151
  end
146
152
 
147
- def initialize(params={})
148
- @attributes, @attributes_before_type_cast = {}, {}
153
+ def initialize(params, timezone)
154
+ @timezone = timezone
155
+ @attributes = {}
156
+ @attributes_before_type_cast = {}
157
+ return unless params
158
+
149
159
  params.each do |attr, value|
150
- self.send("#{attr}=", value)
151
- end if params
160
+ send("#{attr}=", value)
161
+ end
152
162
  end
153
163
 
154
164
  def self.attribute_keys
@@ -157,72 +167,49 @@ module ATDIS
157
167
 
158
168
  # Does what the equivalent on Activerecord does
159
169
  def self.attribute_names
160
- attribute_types.keys.map{|k| k.to_s}
170
+ attribute_types.keys.map(&:to_s)
161
171
  end
162
172
 
163
- def self.cast(value, type)
173
+ def self.cast(value, type, timezone)
164
174
  # If it's already the correct type (or nil) then we don't need to do anything
165
- if value.nil? || value.kind_of?(type)
175
+ if value.nil? || value.is_a?(type)
166
176
  value
167
- # Special handling for arrays. When we typecast arrays we actually typecast each member of the array
168
- elsif value.kind_of?(Array)
169
- value.map {|v| cast(v, type)}
177
+ # Special handling for arrays. When we typecast arrays we actually
178
+ # typecast each member of the array
179
+ elsif value.is_a?(Array)
180
+ value.map { |v| cast(v, type, timezone) }
170
181
  elsif type == DateTime
171
- cast_datetime(value)
182
+ cast_datetime(value, timezone)
172
183
  elsif type == URI
173
184
  cast_uri(value)
174
185
  elsif type == String
175
186
  cast_string(value)
176
- elsif type == Fixnum
177
- cast_fixnum(value)
187
+ elsif type == Integer
188
+ cast_integer(value)
178
189
  elsif type == RGeo::GeoJSON
179
190
  cast_geojson(value)
180
191
  # Otherwise try to use Type.interpret to do the typecasting
181
192
  elsif type.respond_to?(:interpret)
182
- type.interpret(value) if value
193
+ type.interpret(value, timezone) if value
183
194
  else
184
195
  raise
185
196
  end
186
197
  end
187
198
 
188
- private
189
-
190
- def attribute(attr)
191
- @attributes[attr]
192
- end
193
-
194
- def attribute_before_type_cast(attr)
195
- @attributes_before_type_cast[attr]
196
- end
197
-
198
- def attribute=(attr, value)
199
- @attributes_before_type_cast[attr] = value
200
- @attributes[attr] = Model.cast(value, attribute_types[attr.to_sym][0])
201
- end
202
-
203
- def self.cast_datetime(value)
204
- # This would be much easier if we knew we only had to support Ruby 1.9 or greater because it has
205
- # an implementation built in. Because for the time being we need to support Ruby 1.8 as well
206
- # we'll build an implementation of parsing by hand. Ugh.
207
- # Referencing http://www.w3.org/TR/NOTE-datetime
208
- # In section 4.3.1 of ATDIS 1.0.4 it shows two variants of iso 8601, either the full date
209
- # or the full date with hours, seconds, minutes and timezone. We'll assume that these
210
- # are the two variants that are allowed.
211
- if value.respond_to?(:match) && value.match(/^\d\d\d\d-\d\d-\d\d(T\d\d:\d\d:\d\d(Z|(\+|-)\d\d:\d\d))?$/)
212
- begin
213
- DateTime.parse(value)
214
- rescue ArgumentError
215
- nil
216
- end
217
- end
199
+ # If timezone is given in the string then the datetime is read in using
200
+ # the timezone in the string and then converted to the timezone "zone"
201
+ # If the timezone isn't given in the string then the datetime is read
202
+ # in using the timezone in "zone"
203
+ def self.cast_datetime(value, timezone)
204
+ ActiveSupport::TimeZone.new(timezone).iso8601(value).to_datetime
205
+ rescue ArgumentError, KeyError
206
+ nil
218
207
  end
219
208
 
220
209
  def self.cast_uri(value)
221
- begin
222
- URI.parse(value)
223
- rescue URI::InvalidURIError
224
- nil
225
- end
210
+ URI.parse(value)
211
+ rescue URI::InvalidURIError
212
+ nil
226
213
  end
227
214
 
228
215
  def self.cast_string(value)
@@ -230,8 +217,8 @@ module ATDIS
230
217
  end
231
218
 
232
219
  # This casting allows nil values
233
- def self.cast_fixnum(value)
234
- value.to_i if value
220
+ def self.cast_integer(value)
221
+ value&.to_i
235
222
  end
236
223
 
237
224
  def self.cast_geojson(value)
@@ -250,5 +237,20 @@ module ATDIS
250
237
  hash
251
238
  end
252
239
  end
240
+
241
+ private
242
+
243
+ def attribute(attr)
244
+ @attributes[attr]
245
+ end
246
+
247
+ def attribute_before_type_cast(attr)
248
+ @attributes_before_type_cast[attr]
249
+ end
250
+
251
+ def attribute=(attr, value)
252
+ @attributes_before_type_cast[attr] = value
253
+ @attributes[attr] = Model.cast(value, attribute_types[attr.to_sym][0], timezone)
254
+ end
253
255
  end
254
256
  end