lhs 2.2.2 → 3.0.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 (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