hal-interpretation 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 307909b10b6823175a275e546f52f1b2451db046
4
- data.tar.gz: bb0969dc221c78829b4fec9f0f1029395a3875f1
3
+ metadata.gz: 7dd0ca8e27a6128646364bb2d2fc57d341652703
4
+ data.tar.gz: fe9fd9ad161ad54e5cfaa096c95bd2a3ae2005c6
5
5
  SHA512:
6
- metadata.gz: c3cb5970235c8d729f3d7f4eaba0637cfce427fbefeb51f647cfc3f236df8c34e53046c17f3cbc778dacd13fac36a10f36d4783086ebd3282469f17631fb6bf9
7
- data.tar.gz: 345c2f5de8ac2cad5f1fce84fd62848db9f8526bb762df1474fa8a957ad178d96ad4667c723ef3dbdcbe490081fe6bf55f1dfacec51e00f484f3cb7b93d8b9ad
6
+ metadata.gz: bb52b63015894a915d4cab0bf8636a935a2b499d51cff8d3eb9354a305bab97c209de37fe4ca385e822c7739cb23c3bfc1fda61846c719649d5f3c93ed4241b8
7
+ data.tar.gz: 0a21dcf648667768fc5ed137e7a9d64a5414778c08e474071a9f71fe7bc7acfc11f50b13703c2bebbcf7e4b7618ead28581d7e467931be345fe8650c84f9a426
@@ -11,12 +11,26 @@ module HalInterpretation
11
11
  # document.
12
12
  #
13
13
  # attr_name - name of attribute on model to extract
14
+ #
14
15
  # opts - hash of named arguments to method
15
- # :from - JSON path from which to get the value for
16
- # attribute. Default: "/#{attr_name}"
16
+ #
17
+ # :from - JSON path from which to get the value for
18
+ # attribute. Default: "/#{attr_name}".
19
+ #
20
+ # :with - Callable that can extract the value when
21
+ # passed a HalClient::Representation of the item.
22
+ #
23
+ # :coercion - callable with which the raw value should be
24
+ # transformed before being stored.
17
25
  def extract(attr_name, opts={})
18
- from = opts.fetch(:from) { "/#{attr_name}" }
19
- extractors << Extractor.new(attr: attr_name, location: from)
26
+ extractor_opts = {
27
+ attr: attr_name,
28
+ location: opts.fetch(:from) { "/#{attr_name}" }
29
+ }
30
+ extractor_opts[:extraction_proc] = opts.fetch(:with) if opts.key? :with
31
+ extractor_opts[:coercion] = opts[:coercion] if opts.key? :coercion
32
+
33
+ extractors << Extractor.new(extractor_opts)
20
34
  end
21
35
  end
22
36
  end
@@ -4,11 +4,22 @@ module HalInterpretation
4
4
  class Extractor
5
5
  # opts - named args
6
6
  # :attr - name of attribute this object will extact.
7
+ #
7
8
  # :location - JSON path from which to get the value.
8
- def initialize(opts) #attr:, location: "/#{attr}")
9
+ #
10
+ # :extraction_proc - Callable that can extract the value when
11
+ # passed a HalClient::Representation of the item.
12
+ #
13
+ # :coercion - proc to pass the extracted value through before
14
+ # storing it.
15
+ def initialize(opts)
9
16
  @attr = opts.fetch(:attr) { fail ArgumentError, "attr is required" }
10
17
  @location = opts.fetch(:location) { "/#{attr}" }
11
- @pointer = Hana::Pointer.new(location)
18
+ @fetcher = opts.fetch(:extraction_proc) { Hana::Pointer.new(location).method(:eval) }
19
+ @value_coercion = opts.fetch(:coercion) { IDENTITY }
20
+
21
+ fail(ArgumentError, ":coercion must respond to #call") unless
22
+ value_coercion.respond_to? :call
12
23
  end
13
24
 
14
25
  # opts - named args
@@ -19,7 +30,8 @@ module HalInterpretation
19
30
  def extract(opts)
20
31
  from = opts.fetch(:from) { fail ArgumentError, "from is required" }
21
32
  to = opts.fetch(:to) { fail ArgumentError, "to is required" }
22
- to.send "#{attr}=", pointer.eval(from)
33
+
34
+ to.send "#{attr}=", value_coercion.call(fetcher.call(from))
23
35
 
24
36
  []
25
37
  rescue => err
@@ -29,6 +41,8 @@ module HalInterpretation
29
41
  attr_reader :attr, :location
30
42
 
31
43
  protected
32
- attr_reader :pointer
44
+ attr_reader :fetcher, :value_coercion
45
+
46
+ IDENTITY = ->(thing){ thing }
33
47
  end
34
- end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module HalInterpretation
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -0,0 +1,55 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe HalInterpretation::Extractor do
4
+ describe "creation" do
5
+ specify { expect{described_class.new(attr: "first_name", location: "/firstName")}
6
+ .not_to raise_error }
7
+ specify { expect{described_class.new(attr: "first_name", with: ->(hal_repr){ "bob" })}
8
+ .not_to raise_error }
9
+ specify { expect{described_class.new(attr: "first_name", location: "/firstName",
10
+ coercion: ->(){ 42 })}
11
+ .not_to raise_error }
12
+ end
13
+
14
+ context "location based" do
15
+ subject(:extractor) { described_class.new(attr: "first_name", location: "/firstName") }
16
+
17
+ specify { expect{extractor.extract(from: source, to: target)}.not_to raise_error }
18
+
19
+ context "after extraction" do
20
+ before do extractor.extract(from: source, to: target) end
21
+
22
+ specify { expect(target.first_name).to eq "Alice" }
23
+ end
24
+ end
25
+
26
+ context "lambda based" do
27
+ subject(:extractor) { described_class
28
+ .new(attr: "parent", location: "/_links/up",
29
+ extraction_proc: ->(hal_repr) {hal_repr.related_hrefs("up").first}) }
30
+
31
+ specify { expect{extractor.extract(from: source, to: target)}.not_to raise_error }
32
+
33
+ context "after extraction" do
34
+ before do extractor.extract(from: source, to: target) end
35
+
36
+ specify { expect(target.parent).to eq "http://foo" }
37
+ end
38
+ end
39
+
40
+ context "coercion" do
41
+ subject(:extractor) { described_class.new(attr: "bday",
42
+ coercion: ->(val){ Time.parse(val) } ) }
43
+ before do extractor.extract(from: source, to: target) end
44
+
45
+ specify { expect(target.bday).to eq Time.utc(2013,10,10,12,13,14) }
46
+ end
47
+
48
+
49
+ let(:target) { Struct.new(:first_name, :bday, :parent).new }
50
+ let(:source) { HalClient::Representation.new(parsed_json: {
51
+ "firstName" => "Alice",
52
+ "bday" => "2013-10-10T12:13:14Z",
53
+ "_links" => {
54
+ "up" => { "href" => "http://foo" }}}) }
55
+ end
@@ -11,20 +11,28 @@ describe HalInterpretation do
11
11
  item_class test_item_class
12
12
  extract :name
13
13
  extract :latitude, from: "/geo/latitude"
14
+ extract :up, with: ->(hal_repr){hal_repr.related_hrefs("up").first}, from: "/_links/up"
15
+ extract :bday, coercion: ->(val){ Time.parse(val) }
14
16
  end }
15
17
 
16
18
  context "valid single item" do
17
19
  let(:json_doc) { <<-JSON }
18
20
  { "name": "foo"
21
+ ,"bday": "2013-12-11T10:09:08Z"
19
22
  ,"geo": {
20
23
  "latitude": 39.1
21
24
  }
25
+ ,"_links": {
26
+ "up": {"href": "/foo"}
27
+ }
22
28
  }
23
29
  JSON
24
30
 
25
31
  specify { expect(interpreter.items).to have(1).item }
26
32
  specify { expect(interpreter.items.first.name).to eq "foo" }
27
33
  specify { expect(interpreter.items.first.latitude).to eq 39.1 }
34
+ specify { expect(interpreter.items.first.up).to eq "/foo" }
35
+ specify { expect(interpreter.items.first.bday).to eq Time.utc(2013,12,11,10,9,8) }
28
36
  specify { expect(interpreter.problems).to be_empty }
29
37
  end
30
38
 
@@ -32,14 +40,18 @@ describe HalInterpretation do
32
40
  let(:json_doc) { <<-JSON }
33
41
  { "_embedded": {
34
42
  "item": [{ "name": "foo"
43
+ ,"bday": "2013-12-11T10:09:08Z"
35
44
  ,"geo": {
36
45
  "latitude": 39.1
37
46
  }
47
+ ,"_links": { "up": {"href": "/foo"} }
38
48
  }
39
49
  ,{ "name": "bar"
50
+ ,"bday": "2013-12-11T10:09:08Z"
40
51
  ,"geo": {
41
52
  "latitude": 39.2
42
53
  }
54
+ ,"_links": { "up": {"href": "/bar"} }
43
55
  }]
44
56
  }
45
57
  }
@@ -62,6 +74,7 @@ describe HalInterpretation do
62
74
  { "geo": {
63
75
  "latitude": "hello"
64
76
  }
77
+ ,"bday": "yesterday"
65
78
  }
66
79
  JSON
67
80
 
@@ -79,6 +92,8 @@ describe HalInterpretation do
79
92
  .to include matching(%r(/name\b)).and(match(/\bblank\b/i)) }
80
93
  specify { expect(interpreter.problems)
81
94
  .to include matching(%r(/geo/latitude\b)).and(match(/\binvalid value\b/i)) }
95
+ specify { expect(interpreter.problems)
96
+ .to include matching(%r(/bday\b)).and(match(/\bno time\b/i)) }
82
97
  end
83
98
 
84
99
  context "collection w/ invalid attributes" do
@@ -126,7 +141,7 @@ describe HalInterpretation do
126
141
  let(:test_item_class) { Class.new do
127
142
  include ActiveModel::Validations
128
143
 
129
- attr_accessor :name, :latitude
144
+ attr_accessor :name, :latitude, :up, :bday
130
145
 
131
146
  def initialize
132
147
  yield self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hal-interpretation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-21 00:00:00.000000000 Z
11
+ date: 2014-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hal-client
@@ -157,6 +157,7 @@ files:
157
157
  - lib/hal_interpretation/extractor.rb
158
158
  - lib/hal_interpretation/item_interpreter.rb
159
159
  - lib/hal_interpretation/version.rb
160
+ - spec/hal_interpretation/extractor_spec.rb
160
161
  - spec/hal_interpretation_spec.rb
161
162
  - spec/spec_helper.rb
162
163
  homepage: https://github.com/pezra/hal-interpretation
@@ -184,5 +185,6 @@ signing_key:
184
185
  specification_version: 4
185
186
  summary: Build models from HAL documents.
186
187
  test_files:
188
+ - spec/hal_interpretation/extractor_spec.rb
187
189
  - spec/hal_interpretation_spec.rb
188
190
  - spec/spec_helper.rb