halva 0.2.0 → 0.4.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
  SHA256:
3
- metadata.gz: c7540c00f3cbdde45eb5601db5fa7b21fd37da8c6f9f32a12d0f7b351a01c578
4
- data.tar.gz: 858f12ed050776011ca688739717efe5ec31afc2a40940b256dfd52f0f7c15dd
3
+ metadata.gz: 3b7e22a105b03d70350b3e43d8c449edebf1eafc5dc348ebdc9d5247f9d9bf01
4
+ data.tar.gz: 96f911bb17f7fa41ff6ac293adb363eac38f5902f48cd08b9145a551ee554646
5
5
  SHA512:
6
- metadata.gz: a887b14fff4b717594cb14b43371f797ddbe2650753261a578f8eab78dd372f78b2cc9618aaed2c3214d69eda63d19b39acb60590a6c8a6353746c4dd2559028
7
- data.tar.gz: 329b6db4147b2646d7f613bacce0202cf1211af44376e7479ff8f917600a8a29c36dfb3bf7ae66a887858b300e4dd16c2d78499457ba184aaed09e8f80167ea7
6
+ metadata.gz: cf8aedb6cbddcbe4ff987ea66e0cca8840228aa5349fa6887643af6e7b248a8b64d440dde92de30ade4b7c22ef6ef4c9babeb7c781ff351d3aa0f8b56a8ee997
7
+ data.tar.gz: 7a2ff75eb11509ed050e36368b19ad4d55d8274fcd5db5588a3595bb193339f6a39c58f2d77d4909377050d410eaa9f608ef68b4d7f2772265685048e3ec7438
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- halva (0.2.0)
4
+ halva (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,13 +1,20 @@
1
1
  # Halva
2
2
 
3
- HAL-compliant serializer
3
+ HAL-compliant decorator
4
4
 
5
5
  [![Ruby](https://github.com/denblackstache/halva/actions/workflows/main.yml/badge.svg)](https://github.com/denblackstache/halva/actions/workflows/main.yml) [![Gem Version](https://badge.fury.io/rb/halva.svg)](https://badge.fury.io/rb/halva)
6
6
 
7
- Links
7
+ **Links**
8
8
  * [HAL - Hypertext Application Language](https://stateless.co/hal_specification.html)
9
9
  * [Specification Draft](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-08)
10
10
 
11
+ **Goals**
12
+
13
+ * No DSL
14
+ * HAL-compliant
15
+ * Not responsible for the whole presentation layer
16
+ * Simple, extensible, self-discoverable
17
+
11
18
  ## Installation
12
19
 
13
20
  Add this line to your application's Gemfile:
@@ -33,11 +40,25 @@ require 'halva'
33
40
 
34
41
  order = Order.find(1)
35
42
  Halva::Resource.from_model(order)
36
- .embed(Halva::Resource.from_model(order.customer).build, :customer)
43
+ .embed(Halva::Resource.from_model(order.customer), :customer)
37
44
  .link(Halva::Link.new('/orders/1', :self))
38
45
  .link(Halva::Link.new('/orders/1/customer', :customer))
39
- .build
40
-
46
+ .to_h
47
+
48
+ # {
49
+ # :id => 1,
50
+ # :name => "Order Example"
51
+ # :_embedded => {
52
+ # :customer => [{
53
+ # :id => 1,
54
+ # :name => "Customer Example"
55
+ # }]
56
+ # },
57
+ # :_links => {
58
+ # :self => {:href => "/orders/1"},
59
+ # :customer => {:href => "/orders/1/customer"}
60
+ # }
61
+ # }
41
62
  ```
42
63
 
43
64
  ### Representing a collection
@@ -47,11 +68,35 @@ require 'halva'
47
68
 
48
69
  orders = Order.find
49
70
  Halva::Resource.from_empty_model
50
- .embed(orders.map { |order| Halva::Resource.from_model(order).build })
51
- .link(Halva::Link.new('/orders?page=3', :next))
71
+ .embed(orders.map do |order|
72
+ Halva::Resource.from_model(order)
73
+ .link(Halva::Link.new("/orders/#{order.id}", :self))
74
+ end, :'acme:order')
52
75
  .link(Halva::Link.new('/orders?page=2', :self))
76
+ .link(Halva::Link.new('/orders?page=3', :next))
53
77
  .link(Halva::Link.new('/orders?page=1', :prev))
54
- .build
78
+ .link(Halva::Curie.new('https://docs.acme.com/relations/{rel}', 'acme'))
79
+ .to_h
80
+
81
+ # {
82
+ # :_embedded => {
83
+ # :"acme:order" => [{
84
+ # :id => 1,
85
+ # :name => "Example"
86
+ # :_links => {:self => {:href => "/orders/1"} }
87
+ # }]
88
+ # },
89
+ # :_links => {
90
+ # :self => {:href => "/orders/1?page=2"},
91
+ # :next => {:href => "/orders/1?page=3"},
92
+ # :prev => {:href => "/orders/1?page=1"},
93
+ # :curies => [{
94
+ # name: 'acme',
95
+ # href: 'https://docs.acme.com/relations/{rel}',
96
+ # templated: true
97
+ # }]
98
+ # }
99
+ # }
55
100
 
56
101
  ```
57
102
 
data/halva.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['Denis Semenenko']
9
9
  spec.email = ['hypercoderx@gmail.com']
10
10
 
11
- spec.summary = 'HAL-compliant serializer'
11
+ spec.summary = 'HAL-compliant decorator'
12
12
  spec.homepage = 'https://github.com/denblackstache/halva'
13
13
  spec.license = 'MIT'
14
14
  spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Halva
4
+ # Compact URI Link Object
5
+ # See [HAL Draft](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal#section-8.2)
6
+ class Curie
7
+ attr_reader :relation, :href
8
+
9
+ # @param [String] href
10
+ # @param [String] name
11
+ def initialize(href, name)
12
+ @href = href
13
+ @relation = :curies
14
+ @link = Halva::Link.new(@href, @relation, { templated: true, name: name })
15
+ end
16
+
17
+ def to_h
18
+ @link.to_h
19
+ end
20
+ end
21
+ end
data/lib/halva/link.rb CHANGED
@@ -2,10 +2,20 @@
2
2
 
3
3
  module Halva
4
4
  # HAL Link Object
5
- # https://datatracker.ietf.org/doc/html/draft-kelly-json-hal#section-5}
5
+ # See [HAL Draft](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal#section-5)
6
6
  class Link
7
- attr_reader :relation, :href
7
+ attr_reader :relation
8
8
 
9
+ # @param [String] href
10
+ # @param [Symbol] relation
11
+ # @param [Hash] options (templated, type, deprecation, name, profile, title, hreflang)
12
+ # @option options [Boolean] :templated true when the Link Object's "href" property is a URI Template
13
+ # @option options [String] :type a hint to indicate the media type expected when dereferencing the target resource
14
+ # @option options [String] :deprecation indicate that the link is to be deprecated (i.e. removed) at a future date
15
+ # @option options [String] :name a secondary key for selecting Link Objects which share the same relation type
16
+ # @option options [String] :profile a URI that hints about the profile of the target resource
17
+ # @option options [String] :title label for the link with a human-readable identifier
18
+ # @option options [String] :hreflang indicate the language of the target resource
9
19
  def initialize(href, relation, options = {})
10
20
  @href = href
11
21
  @relation = relation.to_sym
@@ -2,10 +2,11 @@
2
2
 
3
3
  module Halva
4
4
  # HAL Resource object
5
- # https://datatracker.ietf.org/doc/html/draft-kelly-json-hal#section-4
5
+ # See [HAL Draft](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal#section-4)
6
6
  class Resource
7
7
  EMBEDDED_KEY = :_embedded
8
8
  LINKS_KEY = :_links
9
+ CURIES_KEY = :curies
9
10
 
10
11
  def self.from_model(model)
11
12
  new(model.to_h)
@@ -16,7 +17,7 @@ module Halva
16
17
  end
17
18
 
18
19
  def initialize(model)
19
- @model = model
20
+ @model = model.freeze
20
21
  @embedded = []
21
22
  @links = []
22
23
  end
@@ -31,22 +32,33 @@ module Halva
31
32
  self
32
33
  end
33
34
 
34
- def build
35
+ def to_h
36
+ document = @model.dup
35
37
  unless @embedded.empty?
36
- @model[EMBEDDED_KEY] = {} unless @model.key?(EMBEDDED_KEY)
38
+ document[EMBEDDED_KEY] = {} unless document.key?(EMBEDDED_KEY)
37
39
  @embedded.each do |emb|
38
- @model[EMBEDDED_KEY][emb[:relation]] = emb[:resource]
40
+ is_collection = emb[:resource].is_a?(Enumerable)
41
+ document[EMBEDDED_KEY][emb[:relation]] = if is_collection
42
+ emb[:resource].map(&:to_h)
43
+ else
44
+ emb[:resource].to_h
45
+ end
39
46
  end
40
47
  end
41
48
 
42
49
  unless @links.empty?
43
- @model[LINKS_KEY] = {} unless @model.key?(LINKS_KEY)
50
+ document[LINKS_KEY] = {} unless document.key?(LINKS_KEY)
44
51
  @links.each do |link|
45
- @model[LINKS_KEY][link.relation] = link.to_h
52
+ if link.relation == CURIES_KEY
53
+ document[LINKS_KEY][CURIES_KEY] = [] unless document[LINKS_KEY].key?(CURIES_KEY)
54
+ document[LINKS_KEY][CURIES_KEY] << link.to_h
55
+ else
56
+ document[LINKS_KEY][link.relation] = link.to_h
57
+ end
46
58
  end
47
59
  end
48
60
 
49
- @model.to_h
61
+ document
50
62
  end
51
63
  end
52
64
  end
data/lib/halva/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Halva
4
- VERSION = '0.2.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/halva.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'halva/curie'
3
4
  require 'halva/link'
4
5
  require 'halva/resource'
5
6
  require 'halva/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: halva
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Semenenko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-21 00:00:00.000000000 Z
11
+ date: 2023-02-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -30,6 +30,7 @@ files:
30
30
  - bin/setup
31
31
  - halva.gemspec
32
32
  - lib/halva.rb
33
+ - lib/halva/curie.rb
33
34
  - lib/halva/link.rb
34
35
  - lib/halva/resource.rb
35
36
  - lib/halva/version.rb
@@ -58,5 +59,5 @@ requirements: []
58
59
  rubygems_version: 3.1.6
59
60
  signing_key:
60
61
  specification_version: 4
61
- summary: HAL-compliant serializer
62
+ summary: HAL-compliant decorator
62
63
  test_files: []