atdis 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Atdis
2
2
 
3
- [![Build Status](https://travis-ci.org/openaustralia/atdis.png?branch=master)](https://travis-ci.org/openaustralia/atdis) [![Coverage Status](https://coveralls.io/repos/openaustralia/atdis/badge.png?branch=master)](https://coveralls.io/r/openaustralia/atdis?branch=master) [![Code Climate](https://codeclimate.com/github/openaustralia/atdis.png)](https://codeclimate.com/github/openaustralia/atdis)
3
+ [![Build Status](https://travis-ci.org/openaustralia/atdis.png?branch=master)](https://travis-ci.org/openaustralia/atdis) [![Coverage Status](https://coveralls.io/repos/openaustralia/atdis/badge.png?branch=master)](https://coveralls.io/r/openaustralia/atdis?branch=master) [![Code Climate](https://codeclimate.com/github/openaustralia/atdis.png)](https://codeclimate.com/github/openaustralia/atdis) [![Gem Version](https://badge.fury.io/rb/atdis.png)](http://badge.fury.io/rb/atdis)
4
4
 
5
5
  A ruby interface to the application tracking data interchange specification (ATDIS) API
6
6
 
7
- We're developing this against version ATDIS 1.0.4.
7
+ We're developing this against version ATDIS 1.0.7.
8
8
 
9
9
  This is **highly alpha** software that probably doesn't yet do what it says on the tin. It is very much a work in progress.
10
10
 
@@ -2,41 +2,72 @@ require 'multi_json'
2
2
 
3
3
  module ATDIS
4
4
  class Application < Model
5
- field_mappings :application => {
6
- :info => {
7
- :dat_id => [:dat_id, String],
8
- :last_modified_date => [:last_modified_date, DateTime],
9
- :description => [:description, String],
10
- :authority => [:authority, String],
11
- :lodgement_date => [:lodgement_date, DateTime],
12
- :determination_date => [:determination_date, DateTime],
13
- :status => [:status, String],
14
- :notification_start_date => [:notification_start_date, DateTime],
15
- :notification_end_date => [:notification_end_date, DateTime],
16
- :officer => [:officer, String],
17
- :estimated_cost => [:estimated_cost, String]
18
- },
19
- :reference => {
20
- :more_info_url => [:more_info_url, URI],
21
- :comments_url => [:comments_url, URI]
22
- },
23
- :location => [:location, Location],
24
- :events => [:events, Event],
25
- :documents => [:documents, Document],
26
- :people => [:people, Person],
27
- :extended => [:extended, Object]
28
- }
29
-
5
+ # TODO When we remove support for Ruby 1.8 we can convert field_mappings back to a hash
6
+ # which is much more readable
7
+ set_field_mappings [
8
+ [:application, [
9
+ [:info, [
10
+ [:dat_id, [:dat_id, String, {:level => 1}]],
11
+ [:last_modified_date, [:last_modified_date, DateTime, {:level => 1}]],
12
+ [:description, [:description, String, {:level => 1}]],
13
+ [:authority, [:authority, String, {:level => 1}]],
14
+ [:lodgement_date, [:lodgement_date, DateTime, {:level => 1}]],
15
+ [:determination_date, [:determination_date, DateTime, {:level => 1}]],
16
+ [:status, [:status, String, {:level => 1}]],
17
+ [:notification_start_date, [:notification_start_date, DateTime, {:level => 1}]],
18
+ [:notification_end_date, [:notification_end_date, DateTime, {:level => 1}]],
19
+ [:officer, [:officer, String, {:level => 1}]],
20
+ [:estimated_cost, [:estimated_cost, String, {:level => 1}]]
21
+ ]],
22
+ [:reference, [
23
+ [:more_info_url, [:more_info_url, URI, {:level => 1}]],
24
+ [:comments_url, [:comments_url, URI, {:level => 1}]]
25
+ ]],
26
+ [:location, [:location, Location, {:level => 1}]],
27
+ [:events, [:events, Event, {:level => 1}]],
28
+ [:documents, [:documents, Document, {:level => 1}]],
29
+ [:people, [:people, Person, {:level => 2}]],
30
+ [:extended, [:extended, Object, {:level => 3}]]
31
+ ]]
32
+ ]
33
+
30
34
  # Mandatory parameters
31
- validates :dat_id, :last_modified_date, :description, :authority, :lodgement_date, :determination_date, :status,
32
- :more_info_url, :location, :presence_before_type_cast => true
35
+ validates :dat_id, :last_modified_date, :description, :authority, :lodgement_date, :determination_date, :status,
36
+ :presence_before_type_cast => {:spec_section => "4.3.1"}
37
+ validates :more_info_url, :presence_before_type_cast => {:spec_section => "4.3.2"}
38
+ validates :location, :presence_before_type_cast => {:spec_section => "4.3.3"}
39
+ validates :events, :presence_before_type_cast => {:spec_section => "4.3.4"}
40
+ validates :documents, :presence_before_type_cast => {:spec_section => "4.3.5"}
33
41
 
34
42
  # Other validations
35
- validates :notification_start_date, :notification_end_date, :last_modified_date, :lodgement_date, :determination_date,
36
- :date_time => true
37
- validates :more_info_url, :http_url => true
38
- validates :location, :valid => true
43
+ validates :last_modified_date, :lodgement_date, :date_time => {:spec_section => "4.3.8"}
44
+ validates :determination_date, :notification_start_date, :notification_end_date, :date_time_or_none => {:spec_section => "4.3.1"}
45
+ validates :more_info_url, :http_url => {:spec_section => "4.3.2"}
46
+ validates :location, :events, :documents, :people, :valid => true
47
+ validates :events, :documents, :array => {:spec_section => "4.3.4"}
48
+ # TODO people should be an array if it's included
49
+
50
+ validate :notification_dates_consistent!
51
+
52
+ def notification_dates_consistent!
53
+ if notification_start_date_before_type_cast == "none" && notification_end_date_before_type_cast != "none"
54
+ errors.add(:notification_start_date, ErrorMessage["can't be none unless notification_end_date is none as well", "4.3.1"])
55
+ end
56
+ if notification_start_date_before_type_cast != "none" && notification_end_date_before_type_cast == "none"
57
+ errors.add(:notification_end_date, ErrorMessage["can't be none unless notification_start_date is none as well", "4.3.1"])
58
+ end
59
+ if notification_start_date_before_type_cast && notification_end_date_before_type_cast.blank?
60
+ errors.add(:notification_end_date, ErrorMessage["can not be blank if notification_start_date is set", "4.3.1"])
61
+ end
62
+ if notification_start_date_before_type_cast.blank? && notification_end_date_before_type_cast
63
+ errors.add(:notification_start_date, ErrorMessage["can not be blank if notification_end_date is set", "4.3.1"])
64
+ end
65
+ if notification_start_date && notification_end_date && notification_start_date > notification_end_date
66
+ errors.add(:notification_end_date, ErrorMessage["can not be earlier than notification_start_date", "4.3.1"])
67
+ end
68
+ end
39
69
 
70
+ # TODO Validate contents of estimated_cost
40
71
  # TODO Validate associated like locations, events, documents, people
41
72
  # TODO Do we need to do extra checking to ensure that events, documents and people are arrays?
42
73
  # TODO Separate validation for L2 and L3 compliance?
@@ -1,12 +1,14 @@
1
1
  module ATDIS
2
2
  class Document < Model
3
- field_mappings :ref => [:ref, String],
4
- :title => [:title, String],
5
- :document_url => [:document_url, URI]
3
+ set_field_mappings [
4
+ [:ref, [:ref, String, {:level => 1}]],
5
+ [:title, [:title, String, {:level => 1}]],
6
+ [:document_url, [:document_url, URI, {:level => 1}]]
7
+ ]
6
8
 
7
9
  # Mandatory parameters
8
- validates :ref, :title, :document_url, :presence_before_type_cast => true
10
+ validates :ref, :title, :document_url, :presence_before_type_cast => {:spec_section => "4.3.5"}
9
11
  # Other validations
10
- validates :document_url, :http_url => true
12
+ validates :document_url, :http_url => {:spec_section => "4.3.5"}
11
13
  end
12
14
  end
data/lib/atdis/event.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  module ATDIS
2
2
  class Event < Model
3
- field_mappings :id => [:id, String],
4
- :date => [:date, DateTime],
5
- :description => [:description, String],
6
- :event_type => [:event_type, String],
7
- :status => [:status, String]
8
-
3
+ set_field_mappings [
4
+ [:id, [:id, String, {:level => 1}]],
5
+ [:date, [:date, DateTime, {:level => 1}]],
6
+ [:description, [:description, String, {:level => 1}]],
7
+ [:event_type, [:event_type, String, {:level => 1}]],
8
+ [:status, [:status, String, {:level => 1}]]
9
+ ]
10
+
9
11
  # Mandatory parameters
10
- validates :id, :date, :description, :presence_before_type_cast => true
12
+ validates :id, :date, :description, :presence_before_type_cast => {:spec_section => "4.3.4"}
11
13
  end
14
+
15
+ # TODO Check that :id is unique within an authority
16
+
12
17
  end
@@ -2,17 +2,20 @@ require "rgeo/geo_json"
2
2
 
3
3
  module ATDIS
4
4
  class Location < Model
5
- field_mappings :address => [:address, String],
6
- :land_title_ref => {
7
- :lot => [:lot, String],
8
- :section => [:section, String],
9
- :dpsp_id => [:dpsp_id, String]
10
- },
11
- :geometry => [:geometry, RGeo::GeoJSON]
12
-
5
+ set_field_mappings [
6
+ [:address, [:address, String, {:level => 1}]],
7
+ [:land_title_ref, [
8
+ [:lot, [:lot, String, {:level => 1}]],
9
+ [:section, [:section, String, {:none_is_nil => true, :level => 1}]],
10
+ [:dpsp_id, [:dpsp_id, String, {:level => 1}]]
11
+ ]],
12
+ [:geometry, [:geometry, RGeo::GeoJSON, {:level => 1}]]
13
+ ]
13
14
  # Mandatory parameters
14
- validates :address, :lot, :section, :dpsp_id, :presence_before_type_cast => true
15
+ validates :address, :lot, :section, :dpsp_id, :presence_before_type_cast => {:spec_section => "4.3.3"}
16
+
17
+ validates :geometry, :geo_json => {:spec_section => "4.3.3"}
15
18
 
16
- validates :geometry, :geo_json => true
19
+ # TODO: Provide warning if dpsp_id doesn't start with "DP" or "SP"
17
20
  end
18
21
  end
data/lib/atdis/model.rb CHANGED
@@ -7,30 +7,39 @@ module ATDIS
7
7
 
8
8
  included do
9
9
  class_attribute :attribute_types
10
- class_attribute :valid_fields
10
+ class_attribute :field_mappings
11
11
  end
12
12
 
13
13
  module ClassMethods
14
+ # of the form {:section=>[String, {:none_is_nil=>true}], :address=>[String]}
14
15
  def casting_attributes(p)
15
16
  define_attribute_methods(p.keys.map{|k| k.to_s})
16
17
  self.attribute_types = p
17
18
  end
18
19
 
19
- def field_mappings(p)
20
+ def set_field_mappings(p)
20
21
  a, b = translate_field_mappings(p)
21
- self.valid_fields = a
22
+ # field_mappings is of the form {:pagination=>{:previous=>:previous_page_no, :pages=>:total_no_pages}}
23
+ self.field_mappings = a
22
24
  casting_attributes(b)
23
25
  end
24
26
 
25
27
  private
28
+
29
+ def leaf_array?(v)
30
+ if !v.kind_of?(Array)
31
+ return false
32
+ end
33
+ v.all?{|a| !a.kind_of?(Array)}
34
+ end
26
35
 
27
36
  def translate_field_mappings(p)
28
- f = {}
29
- ca = {}
37
+ f = ActiveSupport::OrderedHash.new
38
+ ca = ActiveSupport::OrderedHash.new
30
39
  p.each do |k,v|
31
- if v.kind_of?(Array)
40
+ if leaf_array?(v)
32
41
  f[k] = v[0]
33
- ca[v.first] = v[1]
42
+ ca[v.first] = v[1..-1]
34
43
  else
35
44
  f2, ca2 = translate_field_mappings(v)
36
45
  f[k] = f2
@@ -42,6 +51,17 @@ module ATDIS
42
51
  end
43
52
  end
44
53
 
54
+ ErrorMessage = Struct.new :message, :spec_section do
55
+ def empty?
56
+ message.empty?
57
+ end
58
+
59
+ # Make this behave pretty much like a string
60
+ def to_s
61
+ message
62
+ end
63
+ end
64
+
45
65
  class Model
46
66
  include ActiveModel::Validations
47
67
  include Validators
@@ -50,17 +70,128 @@ module ATDIS
50
70
  attribute_method_suffix '_before_type_cast'
51
71
  attribute_method_suffix '='
52
72
 
53
- attr_reader :attributes
73
+ attr_reader :attributes, :attributes_before_type_cast
54
74
  # Stores any part of the json that could not be interpreted. Usually
55
75
  # signals an error if it isn't empty.
56
- attr_accessor :json_left_overs
76
+ attr_accessor :json_left_overs, :json_load_error
57
77
 
58
78
  validate :json_left_overs_is_empty
59
79
 
80
+ def self.level_attribute_names(level)
81
+ attribute_types.find_all{|k,v| (v[1] || {})[:level] == level }.map{|k,v| k.to_s}
82
+ end
83
+
84
+ def json_attribute(a, new_value, mappings = field_mappings)
85
+ mappings.each do |attribute, v|
86
+ if v == a
87
+ return {attribute => new_value}
88
+ end
89
+ if v.kind_of?(Hash)
90
+ r = json_attribute(a, new_value, v)
91
+ if r
92
+ return {attribute => r}
93
+ end
94
+ end
95
+ end
96
+ nil
97
+ end
98
+
99
+ def self.map_field(key, data, mappings)
100
+ mappings.each do |k, v|
101
+ if v == key
102
+ return data[k]
103
+ elsif v.kind_of?(Hash) && data.has_key?(k)
104
+ r = map_field(key, data[k], mappings[k])
105
+ if r
106
+ return r
107
+ end
108
+ end
109
+ end
110
+ nil
111
+ end
112
+
113
+ def self.unused_data(data, mappings = field_mappings)
114
+ json_left_overs = {}
115
+ data.each_key do |key|
116
+ if mappings[key]
117
+ if mappings[key].kind_of?(Hash)
118
+ l2 = unused_data(data[key], mappings[key])
119
+ json_left_overs[key] = l2 unless l2.empty?
120
+ end
121
+ else
122
+ json_left_overs[key] = data[key]
123
+ end
124
+ end
125
+ json_left_overs
126
+ end
127
+
128
+ def self.attribute_names_from_mappings(mappings)
129
+ result = []
130
+ mappings.each do |k, v|
131
+ if v.kind_of?(Hash)
132
+ result += attribute_names_from_mappings(v)
133
+ else
134
+ result << v
135
+ end
136
+ end
137
+ result
138
+ end
139
+
140
+ # Map json structure to our values
141
+ def self.map_fields(data, mappings = field_mappings)
142
+ values = {}
143
+ attribute_names_from_mappings(mappings).each do |attribute|
144
+ values[attribute] = map_field(attribute, data, mappings)
145
+ end
146
+ values
147
+ end
148
+
149
+ def json_errors
150
+ r = []
151
+ errors.messages.each do |attribute, e|
152
+ value = attributes[attribute.to_s]
153
+ if (value.respond_to?(:valid?) && !value.valid?)
154
+ r += value.json_errors.map{|a, b| [json_attribute(attribute, a), b]}
155
+ elsif (value && !value.respond_to?(:valid?) && value.respond_to?(:all?) && !value.all?{|v| v.valid?})
156
+ f = value.find{|v| !v.valid?}
157
+ r += f.json_errors.map{|a, b| [json_attribute(attribute, a), b]}
158
+ else
159
+ r << [json_attribute(attribute, attributes_before_type_cast[attribute.to_s]), e]
160
+ end
161
+ end
162
+ r
163
+ end
164
+
165
+ # TODO This is doing a similar stepping down into the children that json_errors is doing. Would be nice
166
+ # to extract the commond code to make this less horrible and arbitrary
167
+ def level_used_in_children?(level)
168
+ attributes.each_value do |a|
169
+ if a.respond_to?(:level_used?) && a.level_used?(level)
170
+ return true
171
+ elsif a.kind_of?(Array) && a.any?{|b| b.level_used?(level)}
172
+ return true
173
+ end
174
+ end
175
+ false
176
+ end
177
+
178
+ # Have we tried to use this attribute?
179
+ def used_attribute?(a)
180
+ !attributes_before_type_cast[a].nil?
181
+ end
182
+
183
+ def level_used_locally?(level)
184
+ self.class.level_attribute_names(level).any?{|a| used_attribute?(a)}
185
+ end
186
+
187
+ def level_used?(level)
188
+ level_used_locally?(level) || level_used_in_children?(level)
189
+ end
190
+
60
191
  def json_left_overs_is_empty
61
192
  if json_left_overs && !json_left_overs.empty?
62
193
  # We have extra parameters that shouldn't be there
63
- errors.add(:json, "Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}")
194
+ errors.add(:json, ErrorMessage["Unexpected parameters in json data: #{MultiJson.dump(json_left_overs)}", "4"])
64
195
  end
65
196
  end
66
197
 
@@ -77,36 +208,18 @@ module ATDIS
77
208
  end
78
209
 
79
210
  def self.interpret(*params)
80
- new(map_fields(valid_fields, *params))
81
- end
82
-
83
- # Map json structure to our values
84
- def self.map_fields(valid_fields, data)
85
- values = {:json_left_overs => {}}
86
- data.each_key do |key|
87
- if valid_fields[key]
88
- if valid_fields[key].kind_of?(Hash)
89
- v2 = map_fields(valid_fields[key], data[key])
90
- l2 = v2.delete(:json_left_overs)
91
- values = values.merge(v2)
92
- values[:json_left_overs][key] = l2 unless l2.empty?
93
- else
94
- values[valid_fields[key]] = data[key]
95
- end
96
- else
97
- values[:json_left_overs][key] = data[key]
98
- end
99
- end
100
- values
211
+ new(map_fields(*params).merge(:json_left_overs => unused_data(*params)))
101
212
  end
102
213
 
103
- def self.cast(value, type)
214
+ def self.cast(value, type, options = {})
215
+ if options[:none_is_nil] && value == "none"
216
+ nil
104
217
  # If it's already the correct type then we don't need to do anything
105
- if value.kind_of?(type)
218
+ elsif value.kind_of?(type)
106
219
  value
107
220
  # Special handling for arrays. When we typecast arrays we actually typecast each member of the array
108
221
  elsif value.kind_of?(Array)
109
- value.map {|v| cast(v, type)}
222
+ value.map {|v| cast(v, type, options)}
110
223
  elsif type == DateTime
111
224
  cast_datetime(value)
112
225
  elsif type == URI
@@ -137,7 +250,7 @@ module ATDIS
137
250
 
138
251
  def attribute=(attr, value)
139
252
  @attributes_before_type_cast[attr] = value
140
- @attributes[attr] = Model.cast(value, attribute_types[attr.to_sym])
253
+ @attributes[attr] = Model.cast(value, attribute_types[attr.to_sym][0], attribute_types[attr.to_sym][1] || {})
141
254
  end
142
255
 
143
256
  def self.cast_datetime(value)
data/lib/atdis/page.rb CHANGED
@@ -2,39 +2,48 @@ module ATDIS
2
2
  class Page < Model
3
3
  attr_accessor :url
4
4
 
5
- field_mappings :response => [:results, Application],
6
- :count => [:count, Fixnum],
7
- :pagination => {
8
- :previous => [:previous_page_no, Fixnum],
9
- :next => [:next_page_no, Fixnum],
10
- :current => [:current_page_no, Fixnum],
11
- :per_page => [:no_results_per_page, Fixnum],
12
- :count => [:total_no_results, Fixnum],
13
- :pages => [:total_no_pages, Fixnum]
14
- }
5
+ set_field_mappings [
6
+ [:response, [:results, Application, {:level => 1}]],
7
+ [:count, [:count, Fixnum, {:level => 2}]],
8
+ [:pagination, [
9
+ [:previous, [:previous_page_no, Fixnum, {:level => 2}]],
10
+ [:next, [:next_page_no, Fixnum, {:level => 2}]],
11
+ [:current, [:current_page_no, Fixnum, {:level => 2}]],
12
+ [:per_page, [:no_results_per_page, Fixnum, {:level => 2}]],
13
+ [:count, [:total_no_results, Fixnum, {:level => 2}]],
14
+ [:pages, [:total_no_pages, Fixnum, {:level => 2}]]
15
+ ]]
16
+ ]
15
17
 
16
18
  # Mandatory parameters
17
- validates :results, :presence_before_type_cast => true
19
+ validates :results, :presence_before_type_cast => {:spec_section => "4.3"}
18
20
  validates :results, :valid => true
19
21
  validate :count_is_consistent, :all_pagination_is_present, :previous_page_no_is_consistent, :next_page_no_is_consistent
20
22
  validate :current_page_no_is_consistent, :total_no_results_is_consistent
23
+ validate :json_loaded_correctly!
24
+
25
+ def json_loaded_correctly!
26
+ if json_load_error
27
+ errors.add(:json, ErrorMessage["Invalid JSON: #{json_load_error}", nil])
28
+ end
29
+ end
21
30
 
22
31
  # If some of the pagination fields are present all of the required ones should be present
23
32
  def all_pagination_is_present
24
33
  if count || previous_page_no || next_page_no || current_page_no || no_results_per_page ||
25
34
  total_no_results || total_no_pages
26
- errors.add(:count, "should be present if pagination is being used") if count.nil?
27
- errors.add(:current_page_no, "should be present if pagination is being used") if current_page_no.nil?
28
- errors.add(:no_results_per_page, "should be present if pagination is being used") if no_results_per_page.nil?
29
- errors.add(:total_no_results, "should be present if pagination is being used") if total_no_results.nil?
30
- errors.add(:total_no_pages, "should be present if pagination is being used") if total_no_pages.nil?
35
+ errors.add(:count, ErrorMessage["should be present if pagination is being used", "6.5"]) if count.nil?
36
+ errors.add(:current_page_no, ErrorMessage["should be present if pagination is being used", "6.5"]) if current_page_no.nil?
37
+ errors.add(:no_results_per_page, ErrorMessage["should be present if pagination is being used", "6.5"]) if no_results_per_page.nil?
38
+ errors.add(:total_no_results, ErrorMessage["should be present if pagination is being used", "6.5"]) if total_no_results.nil?
39
+ errors.add(:total_no_pages, ErrorMessage["should be present if pagination is being used", "6.5"]) if total_no_pages.nil?
31
40
  end
32
41
  end
33
42
 
34
43
  def count_is_consistent
35
44
  if count
36
- errors.add(:count, "is not the same as the number of applications returned") if count != results.count
37
- errors.add(:count, "should not be larger than the number of results per page") if count > no_results_per_page
45
+ errors.add(:count, ErrorMessage["is not the same as the number of applications returned", "6.5"]) if count != results.count
46
+ errors.add(:count, ErrorMessage["should not be larger than the number of results per page", "6.5"]) if count > no_results_per_page
38
47
  end
39
48
  end
40
49
 
@@ -42,14 +51,14 @@ module ATDIS
42
51
  if current_page_no
43
52
  if previous_page_no
44
53
  if previous_page_no != current_page_no - 1
45
- errors.add(:previous_page_no, "should be one less than current page number or null if first page")
54
+ errors.add(:previous_page_no, ErrorMessage["should be one less than current page number or null if first page", "6.5"])
46
55
  end
47
56
  if current_page_no == 1
48
- errors.add(:previous_page_no, "should be null if on the first page")
57
+ errors.add(:previous_page_no, ErrorMessage["should be null if on the first page", "6.5"])
49
58
  end
50
59
  else
51
60
  if current_page_no > 1
52
- errors.add(:previous_page_no, "can't be null if not on the first page")
61
+ errors.add(:previous_page_no, ErrorMessage["can't be null if not on the first page", "6.5"])
53
62
  end
54
63
  end
55
64
  end
@@ -57,29 +66,29 @@ module ATDIS
57
66
 
58
67
  def next_page_no_is_consistent
59
68
  if next_page_no && next_page_no != current_page_no + 1
60
- errors.add(:next_page_no, "should be one greater than current page number or null if last page")
69
+ errors.add(:next_page_no, ErrorMessage["should be one greater than current page number or null if last page", "6.5"])
61
70
  end
62
71
  if next_page_no.nil? && current_page_no != total_no_pages
63
- errors.add(:next_page_no, "can't be null if not on the last page")
72
+ errors.add(:next_page_no, ErrorMessage["can't be null if not on the last page", "6.5"])
64
73
  end
65
74
  if next_page_no && current_page_no == total_no_pages
66
- errors.add(:next_page_no, "should be null if on the last page")
75
+ errors.add(:next_page_no, ErrorMessage["should be null if on the last page", "6.5"])
67
76
  end
68
77
  end
69
78
 
70
79
  def current_page_no_is_consistent
71
80
  if current_page_no
72
- errors.add(:current_page_no, "is larger than the number of pages") if current_page_no > total_no_pages
73
- errors.add(:current_page_no, "can not be less than 1") if current_page_no < 1
81
+ errors.add(:current_page_no, ErrorMessage["is larger than the number of pages", "6.5"]) if current_page_no > total_no_pages
82
+ errors.add(:current_page_no, ErrorMessage["can not be less than 1", "6.5"]) if current_page_no < 1
74
83
  end
75
84
  end
76
85
 
77
86
  def total_no_results_is_consistent
78
87
  if total_no_pages && total_no_results > total_no_pages * no_results_per_page
79
- errors.add(:total_no_results, "is larger than can be retrieved through paging")
88
+ errors.add(:total_no_results, ErrorMessage["is larger than can be retrieved through paging", "6.5"])
80
89
  end
81
90
  if total_no_pages && total_no_results <= (total_no_pages - 1) * no_results_per_page
82
- errors.add(:total_no_results, "could fit into a smaller number of pages")
91
+ errors.add(:total_no_results, ErrorMessage["could fit into a smaller number of pages", "6.5"])
83
92
  end
84
93
  end
85
94
 
@@ -90,7 +99,14 @@ module ATDIS
90
99
  end
91
100
 
92
101
  def self.read_json(text)
93
- interpret(MultiJson.load(text, :symbolize_keys => true))
102
+ begin
103
+ data = MultiJson.load(text, :symbolize_keys => true)
104
+ interpret(data)
105
+ rescue MultiJson::LoadError => e
106
+ a = interpret({:response => []})
107
+ a.json_load_error = e.to_s
108
+ a
109
+ end
94
110
  end
95
111
 
96
112
  def previous_url