lhs 2.2.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +296 -30
  3. data/lhs.gemspec +3 -3
  4. data/lib/lhs.rb +0 -7
  5. data/lib/lhs/collection.rb +4 -4
  6. data/lib/lhs/concerns/item/destroy.rb +2 -2
  7. data/lib/lhs/concerns/item/save.rb +3 -3
  8. data/lib/lhs/concerns/item/update.rb +2 -2
  9. data/lib/lhs/concerns/item/validation.rb +4 -5
  10. data/lib/lhs/concerns/{service → record}/all.rb +2 -2
  11. data/lib/lhs/concerns/{service → record}/batch.rb +3 -3
  12. data/lib/lhs/concerns/{service → record}/create.rb +4 -3
  13. data/lib/lhs/concerns/{service → record}/endpoints.rb +6 -6
  14. data/lib/lhs/concerns/{service → record}/find.rb +3 -2
  15. data/lib/lhs/concerns/{service → record}/find_by.rb +3 -2
  16. data/lib/lhs/concerns/{service → record}/first.rb +1 -1
  17. data/lib/lhs/concerns/{service → record}/includes.rb +4 -2
  18. data/lib/lhs/concerns/{service → record}/mapping.rb +1 -1
  19. data/lib/lhs/concerns/{service → record}/model.rb +1 -1
  20. data/lib/lhs/concerns/{service → record}/request.rb +12 -12
  21. data/lib/lhs/concerns/{service → record}/where.rb +3 -2
  22. data/lib/lhs/data.rb +25 -53
  23. data/lib/lhs/endpoint.rb +2 -2
  24. data/lib/lhs/item.rb +8 -2
  25. data/lib/lhs/proxy.rb +2 -2
  26. data/lib/lhs/record.rb +42 -0
  27. data/lib/lhs/version.rb +1 -1
  28. data/spec/collection/meta_data_spec.rb +2 -2
  29. data/spec/collection/without_object_items_spec.rb +1 -1
  30. data/spec/data/item_spec.rb +2 -14
  31. data/spec/data/merge_spec.rb +3 -3
  32. data/spec/data/raw_spec.rb +1 -1
  33. data/spec/data/respond_to_spec.rb +3 -3
  34. data/spec/data/root_spec.rb +2 -2
  35. data/spec/data/to_json_spec.rb +2 -2
  36. data/spec/endpoint/for_url_spec.rb +1 -1
  37. data/spec/item/delegate_spec.rb +2 -2
  38. data/spec/item/destroy_spec.rb +4 -4
  39. data/spec/item/errors_spec.rb +4 -4
  40. data/spec/item/getter_spec.rb +2 -2
  41. data/spec/item/internal_data_structure_spec.rb +1 -1
  42. data/spec/item/save_spec.rb +3 -4
  43. data/spec/item/setter_spec.rb +2 -2
  44. data/spec/item/update_spec.rb +2 -2
  45. data/spec/item/validation_spec.rb +47 -75
  46. data/spec/proxy/load_spec.rb +2 -2
  47. data/spec/{service → record}/all_spec.rb +7 -7
  48. data/spec/{service → record}/build_spec.rb +5 -4
  49. data/spec/{service → record}/create_spec.rb +6 -5
  50. data/spec/{service → record}/creation_failed_spec.rb +6 -5
  51. data/spec/record/definitions_spec.rb +29 -0
  52. data/spec/{service → record}/endpoint_misconfiguration_spec.rb +3 -3
  53. data/spec/{service → record}/endpoint_options_spec.rb +4 -4
  54. data/spec/{service → record}/endpoints_spec.rb +15 -15
  55. data/spec/{service → record}/find_by_spec.rb +8 -8
  56. data/spec/{service → record}/find_each_spec.rb +3 -3
  57. data/spec/{service → record}/find_in_batches_spec.rb +6 -6
  58. data/spec/{service → record}/find_spec.rb +10 -9
  59. data/spec/{service → record}/first_spec.rb +7 -6
  60. data/spec/{service → record}/includes_spec.rb +7 -7
  61. data/spec/{service → record}/mapping_spec.rb +27 -16
  62. data/spec/{service → record}/model_name_spec.rb +2 -2
  63. data/spec/{service → record}/new_spec.rb +4 -3
  64. data/spec/{service → record}/request_spec.rb +3 -3
  65. data/spec/record/where_spec.rb +34 -0
  66. data/spec/support/cleanup_endpoints.rb +1 -1
  67. data/spec/support/{cleanup_services.rb → cleanup_records.rb} +2 -2
  68. metadata +60 -67
  69. data/docs/collections.md +0 -28
  70. data/docs/data.md +0 -39
  71. data/docs/items.md +0 -79
  72. data/docs/service.jpg +0 -0
  73. data/docs/service.pdf +2 -650
  74. data/docs/services.md +0 -266
  75. data/lib/lhs/concerns/service/build.rb +0 -19
  76. data/lib/lhs/service.rb +0 -18
  77. data/spec/data/pagination_spec.rb +0 -60
  78. data/spec/dummy/README.rdoc +0 -28
  79. data/spec/service/where_spec.rb +0 -33
@@ -14,9 +14,9 @@ class LHS::Item < LHS::Proxy
14
14
  end
15
15
 
16
16
  def update!(params)
17
- service = _data._root._service
17
+ record = _data._root._record_class
18
18
  _data.merge_raw!(LHS::Data.new(params))
19
- response_data = service.request(
19
+ response_data = record.request(
20
20
  method: :post,
21
21
  url: href,
22
22
  body: _data.to_json,
@@ -8,11 +8,10 @@ class LHS::Item < LHS::Proxy
8
8
  def valid?
9
9
  self.errors = nil
10
10
  fail 'No validation endpoint found!' unless validation_endpoint
11
- service = LHS::Service.for_url(validation_endpoint.url)
12
- validation_params = validation_endpoint.options[:validates] == true ? { persist: false } : { validation_endpoint.options[:validates] => false }
13
- params = validation_endpoint.options.fetch(:params, {}).merge(validation_params)
11
+ record = LHS::Record.for_url(validation_endpoint.url)
12
+ params = validation_endpoint.options.fetch(:params, {}).merge(persist: false)
14
13
  begin
15
- service.request(
14
+ record.request(
16
15
  url: validation_endpoint.url,
17
16
  method: :post,
18
17
  params: params,
@@ -30,7 +29,7 @@ class LHS::Item < LHS::Proxy
30
29
  private
31
30
 
32
31
  def validation_endpoint
33
- endpoint = _data._service.find_endpoint(_data._raw)
32
+ endpoint = _data._record_class.find_endpoint(_data._raw)
34
33
  endpoint ||= LHS::Endpoint.for_url(_data.href) if _data.href
35
34
  validates = endpoint.options && endpoint.options.fetch(:validates, false)
36
35
  fail 'Endpoint does not support validations!' unless validates
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module All
6
6
  extend ActiveSupport::Concern
@@ -26,7 +26,7 @@ class LHS::Service
26
26
  all.concat request(params: params.merge(limit: limit, offset: offset))._raw[:items]
27
27
  end
28
28
  end
29
- LHS::Data.new(all, nil, self)
29
+ data._record_class.new(LHS::Data.new(all, nil, self))
30
30
  end
31
31
  end
32
32
  end
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Batch
6
6
  extend ActiveSupport::Concern
@@ -12,7 +12,7 @@ class LHS::Service
12
12
  find_in_batches(options) do |data|
13
13
  data.each do |record|
14
14
  item = LHS::Item.new(LHS::Data.new(record, data, self))
15
- yield LHS::Data.new(item, data, self)
15
+ yield self.new(LHS::Data.new(item, data, self))
16
16
  end
17
17
  end
18
18
  end
@@ -27,7 +27,7 @@ class LHS::Service
27
27
  data = request(params: params.merge(limit: batch_size, offset: start))
28
28
  batch_size = data._raw[:limit]
29
29
  left = data._raw[:total].to_i - data._raw[:offset].to_i - data._raw[:limit].to_i
30
- yield data
30
+ yield self.new(data)
31
31
  break if left <= 0
32
32
  start += batch_size
33
33
  end
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Create
6
6
  extend ActiveSupport::Concern
@@ -14,12 +14,13 @@ class LHS::Service
14
14
  data = LHS::Data.new(json, nil, self, e.response.request)
15
15
  item = LHS::Item.new(data)
16
16
  item.errors = LHS::Errors.new(e.response)
17
- LHS::Data.new(item, data)
17
+ data._record_class.new(LHS::Data.new(item, data))
18
18
  end
19
19
 
20
20
  def create!(data = {})
21
21
  url = compute_url!(data)
22
- request(url: url, method: :post, body: data.to_json, headers: {'Content-Type' => 'application/json'})
22
+ data = request(url: url, method: :post, body: data.to_json, headers: {'Content-Type' => 'application/json'})
23
+ data._record_class.new(data)
23
24
  end
24
25
  end
25
26
  end
@@ -1,9 +1,9 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  # An endpoint is an url that leads to a backend resource.
6
- # A service can contain multiple endpoints.
6
+ # A record can contain multiple endpoints.
7
7
  # The endpoint that is used to request data is choosen
8
8
  # based on the provided parameters.
9
9
  module Endpoints
@@ -26,16 +26,16 @@ class LHS::Service
26
26
  endpoint = LHC::Endpoint.new(url, options)
27
27
  sanity_check(endpoint)
28
28
  endpoints.push(endpoint)
29
- LHS::Service::Endpoints.all ||= {}
30
- LHS::Service::Endpoints.all[url] = self
29
+ LHS::Record::Endpoints.all ||= {}
30
+ LHS::Record::Endpoints.all[url] = self
31
31
  end
32
32
 
33
33
  def for_url(url)
34
34
  return unless url
35
- template, service = LHS::Service::Endpoints.all.detect do |template, _service|
35
+ template, record = LHS::Record::Endpoints.all.detect do |template, _record_class|
36
36
  LHC::Endpoint.match?(url, template)
37
37
  end
38
- service
38
+ record
39
39
  end
40
40
 
41
41
  # Find an endpoint based on the provided parameters.
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Find
6
6
  extend ActiveSupport::Concern
@@ -9,11 +9,12 @@ class LHS::Service
9
9
 
10
10
  # Find a single uniqe record
11
11
  def find(args)
12
- if args.is_a? Hash
12
+ data = if args.is_a? Hash
13
13
  find_with_parameters(args)
14
14
  else
15
15
  find_by_id(args)
16
16
  end
17
+ data._record_class.new(data)
17
18
  end
18
19
 
19
20
  private
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module FindBy
6
6
  extend ActiveSupport::Concern
@@ -24,11 +24,12 @@ class LHS::Service
24
24
  def _find_by(params)
25
25
  params = params.dup.merge(limit: 1)
26
26
  data = request(params: params)
27
- if data._proxy.is_a?(LHS::Collection)
27
+ data = if data._proxy.is_a?(LHS::Collection)
28
28
  data.first || fail(LHC::NotFound.new('No item was found.', data._request.response))
29
29
  else
30
30
  data
31
31
  end
32
+ data._record_class.new(data)
32
33
  end
33
34
  end
34
35
  end
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module First
6
6
  extend ActiveSupport::Concern
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Includes
6
6
  extend ActiveSupport::Concern
@@ -16,7 +16,9 @@ class LHS::Service
16
16
  end
17
17
 
18
18
  def includes(*args)
19
- class_clone = clone
19
+ name = "#{self}#{args.object_id}"
20
+ constant = Object.const_set(name, self)
21
+ class_clone = constant
20
22
  class_clone.endpoints = endpoints
21
23
  class_clone.mapping = mapping
22
24
  class_clone.including = args.size == 1 ? args[0] : args
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  # Mapping allows to configure some accessors that access data using a provided proc
6
6
  module Mapping
@@ -1,7 +1,7 @@
1
1
  require 'active_support'
2
2
  require 'active_model'
3
3
 
4
- class LHS::Service
4
+ class LHS::Record
5
5
 
6
6
  module Model
7
7
  extend ActiveSupport::Concern
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Request
6
6
  extend ActiveSupport::Concern
@@ -71,12 +71,12 @@ class LHS::Service
71
71
 
72
72
  # Load additional resources that are requested with include
73
73
  def load_include(options, data, sub_includes)
74
- service = service_for_options(options) || self
75
- options = convert_options_to_endpoints(options) if service_for_options(options)
74
+ record = record_for_options(options) || self
75
+ options = convert_options_to_endpoints(options) if record_for_options(options)
76
76
  begin
77
- service.includes(sub_includes).request(options)
77
+ record.includes(sub_includes).request(options)
78
78
  rescue LHC::NotFound
79
- LHS::Data.new({}, data, service)
79
+ LHS::Data.new({}, data, record)
80
80
  end
81
81
  end
82
82
 
@@ -116,17 +116,17 @@ class LHS::Service
116
116
  options
117
117
  end
118
118
 
119
- def service_for_options(options)
120
- services = []
119
+ def record_for_options(options)
120
+ records = []
121
121
  if options.is_a?(Array)
122
122
  options.each do |option|
123
- next unless service = LHS::Service.for_url(option[:url])
124
- services.push(service)
123
+ next unless record = LHS::Record.for_url(option[:url])
124
+ records.push(record)
125
125
  end
126
- fail 'Found more than one service that could be used to do the request' if services.uniq.count > 1
127
- services.uniq.first
126
+ fail 'Found more than one record that could be used to do the request' if records.uniq.count > 1
127
+ records.uniq.first
128
128
  else # Hash
129
- LHS::Service.for_url(options[:url])
129
+ LHS::Record.for_url(options[:url])
130
130
  end
131
131
  end
132
132
 
@@ -1,6 +1,6 @@
1
1
  require 'active_support'
2
2
 
3
- class LHS::Service
3
+ class LHS::Record
4
4
 
5
5
  module Where
6
6
  extend ActiveSupport::Concern
@@ -9,7 +9,8 @@ class LHS::Service
9
9
 
10
10
  # Used to query data from the service.
11
11
  def where(params = {})
12
- request(params: params)
12
+ data = request(params: params)
13
+ data._record_class.new(data)
13
14
  end
14
15
  end
15
16
  end
@@ -6,12 +6,12 @@ class LHS::Data
6
6
  include Json
7
7
 
8
8
  # prevent clashing with attributes of underlying data
9
- attr_accessor :_proxy, :_raw, :_parent, :_service, :_request
9
+ attr_accessor :_proxy, :_raw, :_parent, :_record_class, :_request
10
10
 
11
- def initialize(input, parent = nil, service = nil, request = nil)
11
+ def initialize(input, parent = nil, record = nil, request = nil)
12
12
  self._raw = raw_from_input(input)
13
13
  self._proxy = proxy_from_input(input)
14
- self._service = service
14
+ self._record_class = record
15
15
  self._parent = parent
16
16
  self._request = request
17
17
  end
@@ -30,7 +30,7 @@ class LHS::Data
30
30
  end
31
31
 
32
32
  def class
33
- _root._service
33
+ _root._record_class
34
34
  end
35
35
 
36
36
  # enforce internal data structure to have deep symbolized keys
@@ -39,48 +39,18 @@ class LHS::Data
39
39
  @_raw = raw
40
40
  end
41
41
 
42
- def current_page
43
- offset + 1
44
- end
45
-
46
- def first_page
47
- 1
48
- end
49
-
50
- def last_page
51
- total_pages
52
- end
53
-
54
- def prev_page
55
- current_page - 1
56
- end
57
-
58
- def next_page
59
- current_page + 1
60
- end
61
-
62
- def limit_value
63
- limit
64
- end
65
-
66
- def total_pages
67
- total / limit
42
+ def root_item?
43
+ root_item == self
68
44
  end
69
45
 
70
46
  protected
71
47
 
72
- # Use existing mapping to provide data
73
- # or forward to proxy
74
48
  def method_missing(name, *args, &block)
75
- if mapping = mapping_for(name)
76
- self.instance_exec(&mapping)
77
- else
78
- _proxy.send(name, *args, &block)
79
- end
49
+ _proxy.send(name, *args, &block)
80
50
  end
81
51
 
82
52
  def respond_to_missing?(name, include_all = false)
83
- (root_item? && _root._service.mapping.keys.map(&:to_s).include?(name.to_s)) ||
53
+ (root_item? && _root._record_class.instance_methods.include?(name)) ||
84
54
  _proxy.respond_to?(name, include_all)
85
55
  end
86
56
 
@@ -90,13 +60,6 @@ class LHS::Data
90
60
  !! (input.is_a?(Hash) && input[:items]) || input.is_a?(Array) || _raw.is_a?(Array)
91
61
  end
92
62
 
93
- def mapping_for(name)
94
- service = LHS::Service.for_url(_raw[:href]) if _raw.is_a?(Hash)
95
- service ||= _root._service if root_item? && _root._service
96
- return unless service
97
- service.mapping[name]
98
- end
99
-
100
63
  def root_item
101
64
  return if self._proxy.class != LHS::Item
102
65
  root = root_item = self
@@ -111,10 +74,6 @@ class LHS::Data
111
74
  root_item
112
75
  end
113
76
 
114
- def root_item?
115
- root_item == self
116
- end
117
-
118
77
  def root?
119
78
  _root == self
120
79
  end
@@ -131,15 +90,28 @@ class LHS::Data
131
90
 
132
91
  def raw_from_input(input)
133
92
  if input.is_a?(String) && input.length > 0
134
- JSON.parse(input).deep_symbolize_keys
93
+ raw_from_json_string(input)
135
94
  elsif defined?(input._raw)
136
95
  input._raw
137
96
  elsif defined?(input._data)
138
97
  input._data._raw
139
98
  else
140
- input = input.to_hash if input.class != Hash && input.respond_to?(:to_hash)
141
- input.deep_symbolize_keys! if input.is_a?(Hash)
142
- input
99
+ raw_from_anything_else(input)
143
100
  end
144
101
  end
102
+
103
+ def raw_from_json_string(input)
104
+ json = JSON.parse(input)
105
+ if json.is_a?(Hash)
106
+ json.deep_symbolize_keys
107
+ else
108
+ json
109
+ end
110
+ end
111
+
112
+ def raw_from_anything_else(input)
113
+ input = input.to_hash if input.class != Hash && input.respond_to?(:to_hash)
114
+ input.deep_symbolize_keys! if input.is_a?(Hash)
115
+ input
116
+ end
145
117
  end
@@ -2,10 +2,10 @@
2
2
  class LHS::Endpoint
3
3
 
4
4
  def self.for_url(url)
5
- template, service = LHS::Service::Endpoints.all.detect do |template, _service|
5
+ template, record = LHS::Record::Endpoints.all.detect do |template, _record_class|
6
6
  LHC::Endpoint.match?(url, template)
7
7
  end
8
- service.endpoints.detect { |endpoint| endpoint.url == template } if service
8
+ record.endpoints.detect { |endpoint| endpoint.url == template } if record
9
9
  end
10
10
  end
11
11
 
@@ -58,7 +58,13 @@ class LHS::Item < LHS::Proxy
58
58
  end
59
59
 
60
60
  def handle_hash(value)
61
- LHS::Data.new(value, _data)
61
+ record = LHS::Record.for_url(value[:href]) if value[:href]
62
+ data = LHS::Data.new(value, _data)
63
+ if record
64
+ record.new(data)
65
+ else
66
+ data
67
+ end
62
68
  end
63
69
 
64
70
  def set(name, value)
@@ -81,6 +87,6 @@ class LHS::Item < LHS::Proxy
81
87
  end
82
88
 
83
89
  def date_time_regex
84
- /(?<date>\d{4}-\d{2}-\d{2})?(?<time>T\d{2}:\d{2}:\d{2}(\.\d*.\d{2}:\d{2})*)?/
90
+ /(?<date>\d{4}-\d{2}-\d{2})?(?<time>T\d{2}:\d{2}:\d{2}\.\d*.\d{2}:\d{2})?/
85
91
  end
86
92
  end