atdis 0.3.13 → 0.4.0

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 (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