atdis 0.3.11 → 0.5.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +46 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +0 -4
  5. data/Gemfile +9 -7
  6. data/Guardfile +4 -3
  7. data/Rakefile +4 -2
  8. data/atdis.gemspec +10 -5
  9. data/lib/atdis.rb +2 -0
  10. data/lib/atdis/feed.rb +32 -24
  11. data/lib/atdis/model.rb +108 -95
  12. data/lib/atdis/models/address.rb +10 -4
  13. data/lib/atdis/models/application.rb +12 -9
  14. data/lib/atdis/models/authority.rb +11 -6
  15. data/lib/atdis/models/document.rb +8 -6
  16. data/lib/atdis/models/event.rb +10 -8
  17. data/lib/atdis/models/info.rb +73 -49
  18. data/lib/atdis/models/land_title_ref.rb +15 -7
  19. data/lib/atdis/models/location.rb +9 -7
  20. data/lib/atdis/models/page.rb +36 -21
  21. data/lib/atdis/models/pagination.rb +91 -32
  22. data/lib/atdis/models/person.rb +7 -5
  23. data/lib/atdis/models/reference.rb +7 -5
  24. data/lib/atdis/models/response.rb +5 -3
  25. data/lib/atdis/models/torrens_title.rb +9 -7
  26. data/lib/atdis/separated_url.rb +17 -15
  27. data/lib/atdis/validators.rb +46 -39
  28. data/lib/atdis/version.rb +3 -1
  29. data/spec/atdis/feed_spec.rb +128 -34
  30. data/spec/atdis/model_spec.rb +124 -51
  31. data/spec/atdis/models/address_spec.rb +18 -9
  32. data/spec/atdis/models/application_spec.rb +222 -155
  33. data/spec/atdis/models/authority_spec.rb +45 -15
  34. data/spec/atdis/models/document_spec.rb +10 -4
  35. data/spec/atdis/models/event_spec.rb +23 -11
  36. data/spec/atdis/models/info_spec.rb +197 -113
  37. data/spec/atdis/models/land_title_ref_spec.rb +32 -16
  38. data/spec/atdis/models/location_spec.rb +75 -60
  39. data/spec/atdis/models/page_spec.rb +244 -135
  40. data/spec/atdis/models/pagination_spec.rb +177 -77
  41. data/spec/atdis/models/person_spec.rb +8 -4
  42. data/spec/atdis/models/reference_spec.rb +29 -16
  43. data/spec/atdis/models/response_spec.rb +2 -1
  44. data/spec/atdis/models/torrens_title_spec.rb +24 -18
  45. data/spec/atdis/separated_url_spec.rb +14 -15
  46. data/spec/spec_helper.rb +14 -10
  47. metadata +62 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a12e4aefcd5295f4cc75677251c79e16d1f8b765
4
- data.tar.gz: ad62ec1348b126335f78f618e7cda5d2cc28cd79
3
+ metadata.gz: 569aa3967302c8529a9c74433f54fd105ebe45d7
4
+ data.tar.gz: 0eb50df65474e2d5bc5787994d58c8a282e87e4a
5
5
  SHA512:
6
- metadata.gz: a873c3b343903e1b9bc4820098d43881e9f8bd473ee2ebd919c0d0e2cd8ab9e4a9bc5454daf6ffa10df8e5e578d82517659bc25ecbe446ba4ce12a756c794f88
7
- data.tar.gz: 997b41425821fb3472a618679f455a5be093955275001284f4f5aa8ede14a07251454e851a87e214b649107e66309c095e7c0cd51b8d388b61bdabc773b4ffda
6
+ metadata.gz: b6aa7bae02ff0fa4a4a2776ef4bbb16f7438f2332f5b3e419f2281abebe8f25e8894a2beb50b325ca3ca24dce598b58f9c0580b5de408f1e4fe69f712dd4bd57
7
+ data.tar.gz: 029202949e54506691b3e5c6bb36f2bb73aafd14e707e4ff328b5f739c0a55762a6b35a2f801a5ccbe5d63c8233d23db6c575d40230bf453c2afc4760268f5e7
@@ -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
@@ -1 +1 @@
1
- ruby-2.0.0-p353
1
+ ruby-2.3.1
@@ -1,6 +1,2 @@
1
- language: ruby
2
- rvm:
3
- - "1.9.3"
4
- - "2.0.0"
5
1
  # uncomment this line if your project needs to run something other than `rake`:
6
2
  # script: bundle exec rspec spec
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
@@ -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", "~> 3"
28
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "atdis/version"
2
4
 
3
5
  require "atdis/validators"
@@ -1,23 +1,34 @@
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, :ignore_ssl_certificate
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, ignore_ssl_certificate = false)
13
22
  @base_url = base_url
23
+ @timezone = timezone
24
+ @ignore_ssl_certificate = ignore_ssl_certificate
14
25
  end
15
26
 
16
27
  def applications_url(options = {})
17
28
  invalid_options = options.keys - VALID_OPTIONS
18
- if !invalid_options.empty?
19
- raise "Unexpected options used: #{invalid_options.join(',')}"
20
- end
29
+
30
+ raise "Unexpected options used: #{invalid_options.join(',')}" unless invalid_options.empty?
31
+
21
32
  options[:street] = options[:street].join(",") if options[:street].respond_to?(:join)
22
33
  options[:suburb] = options[:suburb].join(",") if options[:suburb].respond_to?(:join)
23
34
  options[:postcode] = options[:postcode].join(",") if options[:postcode].respond_to?(:join)
@@ -27,7 +38,7 @@ module ATDIS
27
38
  end
28
39
 
29
40
  def application_url(id)
30
- "#{base_url}/#{CGI::escape(id)}.json"
41
+ "#{base_url}/#{CGI.escape(id)}.json"
31
42
  end
32
43
 
33
44
  def self.base_url_from_url(url)
@@ -45,44 +56,39 @@ module ATDIS
45
56
  def self.options_from_url(url)
46
57
  u = URI.parse(url)
47
58
  options = query_to_options(u.query)
48
- [:lodgement_date_start, :lodgement_date_end, :last_modified_date_start, :last_modified_date_end].each do |k|
59
+ %i[lodgement_date_start lodgement_date_end last_modified_date_start
60
+ last_modified_date_end].each do |k|
49
61
  options[k] = Date.parse(options[k]) if options[k]
50
62
  end
51
63
  options[:page] = options[:page].to_i if options[:page]
52
64
  # Remove invalid options
53
- options.keys.each do |key|
54
- if !VALID_OPTIONS.include?(key)
55
- options.delete(key)
56
- end
65
+ options.each_key do |key|
66
+ options.delete(key) unless VALID_OPTIONS.include?(key)
57
67
  end
58
68
  options
59
69
  end
60
70
 
61
71
  def applications(options = {})
62
- Models::Page.read_url(applications_url(options))
72
+ Models::Page.read_url(applications_url(options), timezone, ignore_ssl_certificate)
63
73
  end
64
74
 
65
75
  def application(id)
66
- Models::Application.read_url(application_url(id))
76
+ Models::Application.read_url(application_url(id), timezone, ignore_ssl_certificate)
67
77
  end
68
78
 
69
- private
70
-
71
79
  # Turn a query string of the form "foo=bar&hello=sir" to {foo: "bar", hello: sir"}
72
80
  def self.query_to_options(query)
73
81
  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
82
+ (query || "").split("&").each do |t|
83
+ key, value = t.split("=")
84
+ options[key.to_sym] = (CGI.unescape(value) if value)
79
85
  end
80
86
  options
81
87
  end
82
88
 
83
89
  # Escape but leave commas unchanged (which are valid in query strings)
84
- def self.escape(v)
85
- CGI::escape(v.to_s).gsub('%2C',',')
90
+ def self.escape(value)
91
+ CGI.escape(value.to_s).gsub("%2C", ",")
86
92
  end
87
93
 
88
94
  # Turn an options hash of the form {foo: "bar", hello: "sir"} into a query
@@ -91,7 +97,9 @@ module ATDIS
91
97
  if options.empty?
92
98
  nil
93
99
  else
94
- options.sort{|a,b| a.first.to_s <=> b.first.to_s}.map{|k,v| "#{k}=#{escape(v)}"}.join("&")
100
+ options.sort { |a, b| a.first.to_s <=> b.first.to_s }
101
+ .map { |k, v| "#{k}=#{escape(v)}" }
102
+ .join("&")
95
103
  end
96
104
  end
97
105
  end
@@ -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,54 @@ 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_raw(url, ignore_ssl_certificate = false)
76
+ RestClient::Resource.new(
77
+ url.to_s,
78
+ verify_ssl: (OpenSSL::SSL::VERIFY_NONE if ignore_ssl_certificate)
79
+ ).get.to_str
80
+ end
81
+
82
+ def self.read_url(url, timezone, ignore_ssl_certificate = false)
83
+ r = read_json(read_url_raw(url, ignore_ssl_certificate), timezone)
74
84
  r.url = url.to_s
75
85
  r
76
86
  end
77
87
 
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
88
+ def self.read_json(text, timezone)
89
+ data = MultiJson.load(text, symbolize_keys: true)
90
+ interpret(data, timezone)
91
+ rescue MultiJson::LoadError => e
92
+ a = interpret({ response: [] }, timezone)
93
+ a.json_load_error = e.to_s
94
+ a
87
95
  end
88
96
 
89
- def self.interpret(*params)
90
- used, unused = partition_by_used(*params)
91
- new(used.merge(json_left_overs: unused))
97
+ def self.interpret(data, timezone)
98
+ used, unused = partition_by_used(data)
99
+ new(used.merge(json_left_overs: unused), timezone)
92
100
  end
93
101
 
94
102
  def json_loaded_correctly!
95
- if json_load_error
96
- errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
97
- end
103
+ return unless json_load_error
104
+
105
+ errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
98
106
  end
99
107
 
100
108
  def json_errors_local
101
109
  r = []
102
110
  # First show special json error
103
- if !errors[:json].empty?
104
- r << [nil, errors[:json]]
105
- end
106
111
  errors.keys.each do |attribute|
112
+ r << [nil, errors[:json]] unless errors[:json].empty?
107
113
  # 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
114
+ next if attribute == :json
115
+
116
+ e = errors[attribute]
117
+ next if e.empty?
118
+
119
+ r << [
120
+ { attribute => attributes_before_type_cast[attribute.to_s] },
121
+ e.map { |m| ErrorMessage["#{attribute} #{m}", m.spec_section] }
122
+ ]
112
123
  end
113
124
  r
114
125
  end
@@ -117,12 +128,11 @@ module ATDIS
117
128
  r = []
118
129
  attributes.each do |attribute_as_string, value|
119
130
  attribute = attribute_as_string.to_sym
120
- e = errors[attribute]
121
131
  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
132
+ r += value.json_errors.map { |a, b| [{ attribute => a }, b] }
133
+ elsif value.is_a?(Array)
134
+ f = value.find { |v| v.respond_to?(:json_errors) && !v.json_errors.empty? }
135
+ r += f.json_errors.map { |a, b| [{ attribute => [a] }, b] } if f
126
136
  end
127
137
  end
128
138
  r
@@ -133,22 +143,29 @@ module ATDIS
133
143
  end
134
144
 
135
145
  # Have we tried to use this attribute?
136
- def used_attribute?(a)
137
- !attributes_before_type_cast[a].nil?
146
+ def used_attribute?(attribute)
147
+ !attributes_before_type_cast[attribute].nil?
138
148
  end
139
149
 
140
150
  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
151
+ return unless json_left_overs && !json_left_overs.empty?
152
+
153
+ # We have extra parameters that shouldn't be there
154
+ errors.add(
155
+ :json,
156
+ ErrorMessage["Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}", "4"]
157
+ )
145
158
  end
146
159
 
147
- def initialize(params={})
148
- @attributes, @attributes_before_type_cast = {}, {}
160
+ def initialize(params, timezone)
161
+ @timezone = timezone
162
+ @attributes = {}
163
+ @attributes_before_type_cast = {}
164
+ return unless params
165
+
149
166
  params.each do |attr, value|
150
- self.send("#{attr}=", value)
151
- end if params
167
+ send("#{attr}=", value)
168
+ end
152
169
  end
153
170
 
154
171
  def self.attribute_keys
@@ -157,68 +174,49 @@ module ATDIS
157
174
 
158
175
  # Does what the equivalent on Activerecord does
159
176
  def self.attribute_names
160
- attribute_types.keys.map{|k| k.to_s}
177
+ attribute_types.keys.map(&:to_s)
161
178
  end
162
179
 
163
- def self.cast(value, type)
180
+ def self.cast(value, type, timezone)
164
181
  # 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)
182
+ if value.nil? || value.is_a?(type)
166
183
  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)}
184
+ # Special handling for arrays. When we typecast arrays we actually
185
+ # typecast each member of the array
186
+ elsif value.is_a?(Array)
187
+ value.map { |v| cast(v, type, timezone) }
170
188
  elsif type == DateTime
171
- cast_datetime(value)
189
+ cast_datetime(value, timezone)
172
190
  elsif type == URI
173
191
  cast_uri(value)
174
192
  elsif type == String
175
193
  cast_string(value)
176
- elsif type == Fixnum
177
- cast_fixnum(value)
194
+ elsif type == Integer
195
+ cast_integer(value)
178
196
  elsif type == RGeo::GeoJSON
179
197
  cast_geojson(value)
180
198
  # Otherwise try to use Type.interpret to do the typecasting
181
199
  elsif type.respond_to?(:interpret)
182
- type.interpret(value) if value
200
+ type.interpret(value, timezone) if value
183
201
  else
184
202
  raise
185
203
  end
186
204
  end
187
205
 
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
- DateTime.parse(value)
213
- end
206
+ # If timezone is given in the string then the datetime is read in using
207
+ # the timezone in the string and then converted to the timezone "zone"
208
+ # If the timezone isn't given in the string then the datetime is read
209
+ # in using the timezone in "zone"
210
+ def self.cast_datetime(value, timezone)
211
+ ActiveSupport::TimeZone.new(timezone).iso8601(value).to_datetime
212
+ rescue ArgumentError, KeyError
213
+ nil
214
214
  end
215
215
 
216
216
  def self.cast_uri(value)
217
- begin
218
- URI.parse(value)
219
- rescue URI::InvalidURIError
220
- nil
221
- end
217
+ URI.parse(value)
218
+ rescue URI::InvalidURIError
219
+ nil
222
220
  end
223
221
 
224
222
  def self.cast_string(value)
@@ -226,8 +224,8 @@ module ATDIS
226
224
  end
227
225
 
228
226
  # This casting allows nil values
229
- def self.cast_fixnum(value)
230
- value.to_i if value
227
+ def self.cast_integer(value)
228
+ value&.to_i
231
229
  end
232
230
 
233
231
  def self.cast_geojson(value)
@@ -246,5 +244,20 @@ module ATDIS
246
244
  hash
247
245
  end
248
246
  end
247
+
248
+ private
249
+
250
+ def attribute(attr)
251
+ @attributes[attr]
252
+ end
253
+
254
+ def attribute_before_type_cast(attr)
255
+ @attributes_before_type_cast[attr]
256
+ end
257
+
258
+ def attribute=(attr, value)
259
+ @attributes_before_type_cast[attr] = value
260
+ @attributes[attr] = Model.cast(value, attribute_types[attr.to_sym][0], timezone)
261
+ end
249
262
  end
250
263
  end