hal-interpretation 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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