yaks 0.9.0 → 0.10.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 +4 -4
- data/README.md +158 -56
- data/Rakefile +1 -3
- data/ataru_setup.rb +72 -0
- data/find_missing_tests.rb +34 -0
- data/lib/yaks.rb +8 -10
- data/lib/yaks/breaking_changes.rb +4 -6
- data/lib/yaks/builder.rb +1 -1
- data/lib/yaks/changelog.rb +1 -1
- data/lib/yaks/collection_mapper.rb +8 -5
- data/lib/yaks/collection_resource.rb +0 -1
- data/lib/yaks/config.rb +17 -7
- data/lib/yaks/configurable.rb +20 -14
- data/lib/yaks/default_policy.rb +82 -33
- data/lib/yaks/format.rb +7 -3
- data/lib/yaks/format/collection_json.rb +4 -4
- data/lib/yaks/format/hal.rb +1 -2
- data/lib/yaks/format/halo.rb +2 -4
- data/lib/yaks/format/json_api.rb +46 -27
- data/lib/yaks/html5_forms.rb +0 -2
- data/lib/yaks/mapper.rb +5 -5
- data/lib/yaks/mapper/association.rb +7 -7
- data/lib/yaks/mapper/association_mapper.rb +2 -0
- data/lib/yaks/mapper/attribute.rb +10 -4
- data/lib/yaks/mapper/config.rb +2 -2
- data/lib/yaks/mapper/form.rb +4 -10
- data/lib/yaks/mapper/form/config.rb +16 -17
- data/lib/yaks/mapper/form/dynamic_field.rb +1 -1
- data/lib/yaks/mapper/form/field.rb +16 -7
- data/lib/yaks/mapper/form/field/option.rb +5 -4
- data/lib/yaks/mapper/form/fieldset.rb +1 -1
- data/lib/yaks/mapper/form/legend.rb +18 -0
- data/lib/yaks/mapper/has_many.rb +1 -0
- data/lib/yaks/mapper/link.rb +7 -4
- data/lib/yaks/null_resource.rb +4 -5
- data/lib/yaks/pipeline.rb +2 -2
- data/lib/yaks/primitivize.rb +3 -2
- data/lib/yaks/reader/hal.rb +12 -13
- data/lib/yaks/reader/json_api.rb +50 -33
- data/lib/yaks/resource.rb +6 -7
- data/lib/yaks/resource/form.rb +2 -12
- data/lib/yaks/resource/form/field.rb +4 -3
- data/lib/yaks/resource/form/field/option.rb +1 -1
- data/lib/yaks/resource/form/fieldset.rb +1 -1
- data/lib/yaks/resource/form/legend.rb +18 -0
- data/lib/yaks/resource/has_fields.rb +13 -7
- data/lib/yaks/resource/link.rb +1 -1
- data/lib/yaks/runner.rb +5 -2
- data/lib/yaks/serializer.rb +2 -3
- data/lib/yaks/util.rb +7 -8
- data/lib/yaks/version.rb +1 -1
- data/spec/acceptance/acceptance_spec.rb +53 -38
- data/spec/acceptance/json_shared_examples.rb +45 -12
- data/spec/acceptance/models.rb +1 -1
- data/spec/integration/dynamic_form_fields_spec.rb +0 -1
- data/spec/integration/fieldset_spec.rb +18 -20
- data/spec/integration/map_to_resource_spec.rb +6 -6
- data/spec/json/{confucius.collection.json → confucius.collection_json.json} +0 -0
- data/spec/json/confucius.json_api.json +43 -27
- data/spec/json/list_of_quotes.collection_json.json +43 -0
- data/spec/json/list_of_quotes.hal.json +18 -0
- data/spec/json/list_of_quotes.json_api.json +25 -0
- data/spec/json/youtypeitwepostit.collection_json.json +45 -0
- data/spec/spec_helper.rb +4 -3
- data/spec/support/classes_for_policy_testing.rb +38 -14
- data/spec/support/deep_eql.rb +21 -18
- data/spec/support/pet_mapper.rb +2 -0
- data/spec/support/shared_contexts.rb +9 -9
- data/spec/unit/yaks/builder_spec.rb +41 -18
- data/spec/unit/yaks/collection_mapper_spec.rb +22 -19
- data/spec/unit/yaks/collection_resource_spec.rb +16 -8
- data/spec/unit/yaks/config_spec.rb +215 -19
- data/spec/unit/yaks/configurable_spec.rb +66 -7
- data/spec/unit/yaks/default_policy/derive_mapper_from_collection_spec.rb +47 -0
- data/spec/unit/yaks/default_policy/derive_mapper_from_item_spec.rb +114 -0
- data/spec/unit/yaks/default_policy/derive_mapper_from_object_spec.rb +29 -71
- data/spec/unit/yaks/default_policy_spec.rb +4 -5
- data/spec/unit/yaks/format/collection_json_spec.rb +35 -36
- data/spec/unit/yaks/format/hal_spec.rb +3 -3
- data/spec/unit/yaks/format/json_api_spec.rb +109 -68
- data/spec/unit/yaks/format_spec.rb +34 -0
- data/spec/unit/yaks/fp/callable_spec.rb +5 -3
- data/spec/unit/yaks/mapper/association_mapper_spec.rb +22 -4
- data/spec/unit/yaks/mapper/association_spec.rb +23 -11
- data/spec/unit/yaks/mapper/attribute_spec.rb +46 -7
- data/spec/unit/yaks/mapper/config_spec.rb +2 -3
- data/spec/unit/yaks/mapper/form/config_spec.rb +95 -0
- data/spec/unit/yaks/mapper/form/dynamic_field_spec.rb +30 -0
- data/spec/unit/yaks/mapper/form/field/option_spec.rb +48 -4
- data/spec/unit/yaks/mapper/form/field_spec.rb +43 -2
- data/spec/unit/yaks/mapper/form/fieldset_spec.rb +67 -8
- data/spec/unit/yaks/mapper/form/legend_spec.rb +52 -0
- data/spec/unit/yaks/mapper/form_spec.rb +84 -23
- data/spec/unit/yaks/mapper/has_many_spec.rb +39 -36
- data/spec/unit/yaks/mapper/has_one_spec.rb +28 -20
- data/spec/unit/yaks/mapper/link_spec.rb +68 -16
- data/spec/unit/yaks/mapper_spec.rb +118 -30
- data/spec/unit/yaks/null_resource_spec.rb +83 -52
- data/spec/unit/yaks/pipeline_spec.rb +101 -74
- data/spec/unit/yaks/primitivize_spec.rb +25 -6
- data/spec/unit/yaks/resource/form/field_spec.rb +5 -5
- data/spec/unit/yaks/resource/form/fieldset_spec.rb +7 -0
- data/spec/unit/yaks/resource/form/legend_spec.rb +8 -0
- data/spec/unit/yaks/resource/form_spec.rb +17 -37
- data/spec/unit/yaks/resource/has_fields_spec.rb +44 -3
- data/spec/unit/yaks/resource/link_spec.rb +11 -6
- data/spec/unit/yaks/resource_spec.rb +87 -98
- data/spec/unit/yaks/runner_spec.rb +112 -28
- data/spec/unit/yaks/serializer_spec.rb +1 -1
- data/spec/unit/yaks/util_spec.rb +30 -10
- data/spec/yaml/list_of_quotes.yaml +13 -0
- data/yaks.gemspec +21 -13
- metadata +129 -41
- data/lib/yaks/attributes.rb +0 -86
- data/lib/yaks/fp.rb +0 -26
- data/lib/yaks/identifier/link_relation.rb +0 -17
- data/resources/iana-link-relations.csv +0 -152
- data/spec/json/youtypeitwepostit.collection.json +0 -45
- data/spec/unit/yaks/attributes_spec.rb +0 -178
- data/spec/unit/yaks/fp_spec.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e26f0f65962ea64eee11346ede1401347525188
|
|
4
|
+
data.tar.gz: 40881b570c5b8145e79a92251a35275b62da9994
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b4370186b9d44d56404df20e65bfb58bedd666b6bd5be2cb78684d1022ed74bb2df1a01c6381dc743c9769cadbdc3fcff441d52298108137a4fe60f873c2dab
|
|
7
|
+
data.tar.gz: 340ea7d369824f9ac7d0ea98e0995c0d4192b63c6a66f9faff2033b78b7b281d494c9044508c7a9bdd085e8a20ffb76b89a54716aef447c8824a27d3080a37ff
|
data/README.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
[][gem]
|
|
2
2
|
[][travis]
|
|
3
|
-
[][gemnasium]
|
|
4
3
|
[][codeclimate]
|
|
5
4
|
[][gitter]
|
|
6
5
|
|
|
7
6
|
[gem]: https://rubygems.org/gems/yaks
|
|
8
7
|
[travis]: https://travis-ci.org/plexus/yaks
|
|
9
|
-
[gemnasium]: https://gemnasium.com/plexus/yaks
|
|
10
8
|
[codeclimate]: https://codeclimate.com/github/plexus/yaks
|
|
11
9
|
[gitter]: https://gitter.im/plexus/yaks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
|
12
10
|
|
|
13
11
|
# Yaks
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
<img align="left" src="https://raw.githubusercontent.com/plexus/yaks/master/logo.png">
|
|
16
14
|
|
|
17
15
|
The library that understands hypermedia.
|
|
18
16
|
|
|
17
|
+
**If you use Yaks please help out by filling out the [Yaks Users Survey](https://docs.google.com/forms/d/1sZB03Vf32igmNmJ7RP8mo8H4VZHcVIpSrUSbvx2xD8s/viewform)**
|
|
18
|
+
|
|
19
19
|
Yaks takes your data and transforms it into hypermedia formats such as
|
|
20
20
|
HAL, JSON-API, or HTML. It allows you to build APIs that are
|
|
21
21
|
discoverable and browsable. It is built from the ground up around
|
|
@@ -33,21 +33,48 @@ requested. These formats are presently supported:
|
|
|
33
33
|
* HALO
|
|
34
34
|
* Transit
|
|
35
35
|
|
|
36
|
-
##
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
[
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
## Table of Contents
|
|
37
|
+
|
|
38
|
+
- [State of Development](#user-content-state-of-development)
|
|
39
|
+
- [Concepts](#user-content-concepts)
|
|
40
|
+
- [Mappers](#user-content-mappers)
|
|
41
|
+
- [Attributes](#user-content-attributes)
|
|
42
|
+
- [Forms](#user-content-forms)
|
|
43
|
+
- [Filtering](#user-content-filtering)
|
|
44
|
+
- [Links](#user-content-links)
|
|
45
|
+
- [Associations](#user-content-associations)
|
|
46
|
+
- [Calling Yaks](#user-content-calling-yaks)
|
|
47
|
+
- [Rack env](#user-content-rack-env)
|
|
48
|
+
- [Namespace](#user-content-namespace)
|
|
49
|
+
- [Custom attribute/link/subresource handling](#user-content-custom-attributelinksubresource-handling)
|
|
50
|
+
- [Resources, Formatters, Serializers](#user-content-resources-formatters-serializers)
|
|
51
|
+
- [Formats](#user-content-formats)
|
|
52
|
+
- [HAL](#user-content-hal)
|
|
53
|
+
- [HTML](#user-content-html)
|
|
54
|
+
- [JSON-API](#user-content-json-api)
|
|
55
|
+
- [Collection+JSON](#user-content-collection-json)
|
|
56
|
+
- [Transit](#user-content-transit)
|
|
57
|
+
- [Hooks](#user-content-hooks)
|
|
58
|
+
- [Policy over Configuration](#user-content-policy-over-configuration)
|
|
59
|
+
- [derive_mapper_from_object](#user-content-derive_mapper_from_object)
|
|
60
|
+
- [derive_mapper_from_association](#user-content-derive_mapper_from_association)
|
|
61
|
+
- [derive_rel_from_association](#user-content-derive_rel_from_association)
|
|
62
|
+
- [Primitivizer](#user-content-primitivizer)
|
|
63
|
+
- [Integration](#user-content-integration)
|
|
64
|
+
- [Real World Usage](#user-content-real-world-usage)
|
|
65
|
+
- [Demo](#user-content-demo)
|
|
66
|
+
- [Cookbook](#user-content-cookbook)
|
|
67
|
+
- [Standards Based](#user-content-standards-based)
|
|
68
|
+
- [How to contribute](#user-content-how-to-contribute)
|
|
69
|
+
- [License](#user-content-license)
|
|
42
70
|
|
|
43
|
-
|
|
44
|
-
to grow and improve. The aim is to create *the reference* for
|
|
45
|
-
supporting hypermedia formats in Ruby.
|
|
71
|
+
## State of Development
|
|
46
72
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
73
|
+
Recent focus has been on stabilizing the core classes, improving
|
|
74
|
+
format support, and increasing test (mutation) coverage. We are
|
|
75
|
+
committed to a stable public API and semantic version. On the 0.x line
|
|
76
|
+
the minor version is bumped when non-backwards compatible changes are
|
|
77
|
+
introduced. After 1.x regular semver conventions will be used.
|
|
51
78
|
|
|
52
79
|
## Concepts
|
|
53
80
|
|
|
@@ -59,13 +86,13 @@ yaks = Yaks.new do
|
|
|
59
86
|
default_format :hal
|
|
60
87
|
rel_template 'http://api.example.com/rels/{rel}'
|
|
61
88
|
format_options(:hal, plural_links: [:copyright])
|
|
62
|
-
|
|
89
|
+
mapper_namespace ::MyAPI
|
|
63
90
|
json_serializer do |data|
|
|
64
|
-
|
|
91
|
+
JSON.dump(data)
|
|
65
92
|
end
|
|
66
93
|
end
|
|
67
94
|
|
|
68
|
-
yaks.call(
|
|
95
|
+
yaks.call(product)
|
|
69
96
|
```
|
|
70
97
|
|
|
71
98
|
Yaks performs this serialization in three steps
|
|
@@ -115,12 +142,12 @@ yaks = Yaks.new do
|
|
|
115
142
|
format_options(:hal, plural_links: [:copyright])
|
|
116
143
|
end
|
|
117
144
|
|
|
118
|
-
yaks.call(post, mapper: PostMapper, format: :hal)
|
|
145
|
+
yaks.call(post, mapper: ::PostMapper, format: :hal)
|
|
119
146
|
```
|
|
120
147
|
|
|
121
148
|
### Attributes
|
|
122
149
|
|
|
123
|
-
Use the `attributes` DSL
|
|
150
|
+
Use the `attribute` or `attributes` DSL methods to specify which attributes of your model you want to expose, as in the example above. You can override the `load_attribute` method to change how attributes are fetched from the model.
|
|
124
151
|
|
|
125
152
|
For example, if you are representing data that is stored in a Hash, you could do
|
|
126
153
|
|
|
@@ -134,12 +161,14 @@ class PostHashMapper < Yaks::Mapper
|
|
|
134
161
|
end
|
|
135
162
|
end
|
|
136
163
|
```
|
|
137
|
-
|
|
138
|
-
The default implementation will first try to find a matching method for an attribute on the mapper itself, and will then fall back to calling the actual model. So you can add extra 'virtual' attributes like so :
|
|
164
|
+
The `attribute` method may also take a block that will be called with the context of the mapper instance. The default implementation will use the block if provided, otherwise it will first try to find a matching method for an attribute on the mapper itself, and will then fall back to calling the actual model. So you can add extra 'virtual' attributes like so :
|
|
139
165
|
|
|
140
166
|
```ruby
|
|
141
167
|
class CommentMapper < Yaks::Mapper
|
|
142
|
-
attributes :
|
|
168
|
+
attributes :body, :date
|
|
169
|
+
attribute :id do
|
|
170
|
+
"Id-#{object.id}"
|
|
171
|
+
end
|
|
143
172
|
|
|
144
173
|
def date
|
|
145
174
|
object.created_at.strftime("at %I:%M%p")
|
|
@@ -176,7 +205,7 @@ rendering of forms, dynamic form sections, ...
|
|
|
176
205
|
You can override `#attributes`, or `#associations`.
|
|
177
206
|
|
|
178
207
|
```ruby
|
|
179
|
-
class SongMapper
|
|
208
|
+
class SongMapper < Yaks::Mapper
|
|
180
209
|
attributes :title, :duration, :lyrics
|
|
181
210
|
|
|
182
211
|
has_one :artist
|
|
@@ -257,7 +286,7 @@ confirming an order, the previously held cart is no longer valid, you
|
|
|
257
286
|
could use the IANA standard `invalidates` rel to communicate this.
|
|
258
287
|
|
|
259
288
|
``` ruby
|
|
260
|
-
class OrderMapper <
|
|
289
|
+
class OrderMapper < Yaks::Mapper
|
|
261
290
|
link :invalidates, '/api/cart', if: ->{ env['api.invalidate_cart'] }
|
|
262
291
|
end
|
|
263
292
|
```
|
|
@@ -296,10 +325,7 @@ it the data to be serialized, plus options.
|
|
|
296
325
|
When serializing, Yaks lets you pass in an `env` hash, which will be made available to all mappers.
|
|
297
326
|
|
|
298
327
|
```ruby
|
|
299
|
-
|
|
300
|
-
yaks.call(foo, env: my_env)
|
|
301
|
-
|
|
302
|
-
class FooMapper
|
|
328
|
+
class FooMapper < Yaks::Mapper
|
|
303
329
|
attributes :bar
|
|
304
330
|
|
|
305
331
|
def bar
|
|
@@ -308,6 +334,9 @@ class FooMapper
|
|
|
308
334
|
end
|
|
309
335
|
end
|
|
310
336
|
end
|
|
337
|
+
|
|
338
|
+
yaks = Yaks.new
|
|
339
|
+
yaks.call(foo, env: my_env)
|
|
311
340
|
```
|
|
312
341
|
|
|
313
342
|
The env hash will be available to all mappers, so you can use this to
|
|
@@ -327,7 +356,7 @@ Yaks by default will find your mappers for you if they follow the
|
|
|
327
356
|
naming convention of appending 'Mapper' to the model class name. This
|
|
328
357
|
(and all other "conventions") can be easily redefined though, see the
|
|
329
358
|
<a href="#policy">policy</a> section. If you have your mappers inside a
|
|
330
|
-
module, use `
|
|
359
|
+
module, use `mapper_namespace`.
|
|
331
360
|
|
|
332
361
|
```ruby
|
|
333
362
|
module API
|
|
@@ -339,7 +368,7 @@ module API
|
|
|
339
368
|
end
|
|
340
369
|
|
|
341
370
|
yaks = Yaks.new do
|
|
342
|
-
|
|
371
|
+
mapper_namespace API::Mappers
|
|
343
372
|
end
|
|
344
373
|
```
|
|
345
374
|
|
|
@@ -498,7 +527,9 @@ If you would like to see better JSON-API support, get in touch. We
|
|
|
498
527
|
might be able to work something out.
|
|
499
528
|
|
|
500
529
|
```ruby
|
|
501
|
-
|
|
530
|
+
Yaks.new do
|
|
531
|
+
default_format :json_api
|
|
532
|
+
end
|
|
502
533
|
```
|
|
503
534
|
|
|
504
535
|
JSON-API has no concept of outbound links, so these will not be
|
|
@@ -506,8 +537,8 @@ rendered. Instead the key will be inferred from the mapper class name
|
|
|
506
537
|
by default. This can be changed per mapper:
|
|
507
538
|
|
|
508
539
|
```ruby
|
|
509
|
-
class AnimalMapper
|
|
510
|
-
|
|
540
|
+
class AnimalMapper < Yaks::Mapper
|
|
541
|
+
type :pet
|
|
511
542
|
end
|
|
512
543
|
```
|
|
513
544
|
|
|
@@ -528,10 +559,12 @@ option can be used. It will map the specified form to a CJ template. Please
|
|
|
528
559
|
notice that CJ only allows one template per representation.
|
|
529
560
|
|
|
530
561
|
```ruby
|
|
531
|
-
|
|
562
|
+
Yaks.new do
|
|
563
|
+
default_format :collection_json
|
|
532
564
|
|
|
533
|
-
collection_json = Yaks.new do
|
|
534
|
-
|
|
565
|
+
collection_json = Yaks.new do
|
|
566
|
+
format_options :collection_json, template: :my_template_form
|
|
567
|
+
end
|
|
535
568
|
end
|
|
536
569
|
|
|
537
570
|
class PostMapper < Yaks::Mapper
|
|
@@ -589,10 +622,20 @@ In Yaks whenever missing values need to be inferred, like finding an unspecified
|
|
|
589
622
|
|
|
590
623
|
```ruby
|
|
591
624
|
yaks = Yaks.new do
|
|
625
|
+
mapper_for Post, SpecialMapper
|
|
626
|
+
|
|
592
627
|
derive_mapper_from_object do |model|
|
|
593
628
|
# ...
|
|
594
629
|
end
|
|
595
630
|
|
|
631
|
+
derive_mapper_from_collection do |collection|
|
|
632
|
+
# ...
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
derive_mapper_from_item do |model|
|
|
636
|
+
# ...
|
|
637
|
+
end
|
|
638
|
+
|
|
596
639
|
derive_type_from_mapper_class do |mapper_class|
|
|
597
640
|
# ...
|
|
598
641
|
end
|
|
@@ -607,15 +650,18 @@ yaks = Yaks.new do
|
|
|
607
650
|
end
|
|
608
651
|
```
|
|
609
652
|
|
|
653
|
+
Note that within these blocks, you may call `super()` which would call
|
|
654
|
+
the default implementation.
|
|
655
|
+
|
|
610
656
|
You can also subclass or create from scratch your own policy class
|
|
611
657
|
|
|
612
658
|
```ruby
|
|
613
|
-
class MyPolicy < DefaultPolicy
|
|
659
|
+
class MyPolicy < Yaks::DefaultPolicy
|
|
614
660
|
#...
|
|
615
661
|
end
|
|
616
662
|
|
|
617
663
|
yaks = Yaks.new do
|
|
618
|
-
|
|
664
|
+
policy_class MyPolicy
|
|
619
665
|
end
|
|
620
666
|
```
|
|
621
667
|
|
|
@@ -632,11 +678,35 @@ yaks.call(array_of_widgets, mapper: MyCollectionMapper, item_mapper: WidgetMappe
|
|
|
632
678
|
```
|
|
633
679
|
|
|
634
680
|
If the mapper is left unspecified, Yaks will inspect whatever you pass
|
|
635
|
-
it
|
|
681
|
+
it. First it will test the given object against the mappings defined using `mapper_for`.
|
|
682
|
+
If no mapper is found, it will call `derive_mapper_from_item` or `derive_mapper_from_collection`
|
|
683
|
+
depending on whether the given object is a collection or not. If the object responds
|
|
684
|
+
to `to_ary` it is considered a collection.
|
|
685
|
+
|
|
686
|
+
### mapper_for
|
|
687
|
+
|
|
688
|
+
This method allows you to define a one-to-one mapping between a mapping rule and a mapper class.
|
|
689
|
+
During the lookup, Yaks will check if any mapping rule matches the given object using the `#===`
|
|
690
|
+
operator.
|
|
691
|
+
|
|
692
|
+
Here are a few examples on how to use it:
|
|
693
|
+
```ruby
|
|
694
|
+
yaks = Yaks.new do
|
|
695
|
+
mapper_for(:home, HomeMapper)
|
|
696
|
+
mapper_for(Post, SpecialMapper)
|
|
697
|
+
mapper_for(->(author) { author.respond_to?(:name) && author.name == 'doh' }, AuthorMapper)
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
yaks.call(:home) # would map using HomeMapper
|
|
701
|
+
yaks.call(Post.new) # would map using PostMapper
|
|
702
|
+
yaks.call(Author.new(name: 'doh')) # would map using AuthorMapper
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### derive_mapper_from_collection
|
|
706
|
+
This method will try various constant lookups based on naming. These all happen
|
|
636
707
|
in the configured namespace, which defaults to the Ruby top level.
|
|
637
708
|
|
|
638
|
-
If the object
|
|
639
|
-
the first object in the collection has a class of `Widget`, and the
|
|
709
|
+
If the first object in the collection has a class of `Widget`, and the
|
|
640
710
|
configured namespace is `API`, then these are tried in turn
|
|
641
711
|
|
|
642
712
|
* `API::WidgetCollectionMapper`
|
|
@@ -649,13 +719,35 @@ it's important that empty collections are handled by the right mapper
|
|
|
649
719
|
(e.g. to set a specific `self` or `profile` link), then you have to be
|
|
650
720
|
explicit.
|
|
651
721
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
722
|
+
### derive_mapper_from_item
|
|
723
|
+
|
|
724
|
+
When using this method, the lookup happens based on the class name,
|
|
725
|
+
and will traverse up the class hierarchy in the configured namespace if
|
|
726
|
+
no suitable mapper is found. Take the following
|
|
727
|
+
code:
|
|
728
|
+
```ruby
|
|
729
|
+
module Stuff
|
|
730
|
+
class Thing ; end
|
|
731
|
+
class Widget < Thing ; end
|
|
732
|
+
end
|
|
733
|
+
```
|
|
734
|
+
The lookup we'll be done as followed.
|
|
735
|
+
|
|
736
|
+
* If the `namespace` option is set (to `Mappers` for example):
|
|
737
|
+
* `Mappers::Stuff::WidgetMapper`
|
|
738
|
+
* `Mappers::Stuff::ThingMapper`
|
|
739
|
+
* `Mappers::Stuff::ObjectMapper`
|
|
740
|
+
* `Mappers::Stuff::BasicObjectMapper`
|
|
741
|
+
* `Mappers::WidgetMapper`
|
|
742
|
+
* `Mappers::ThingMapper`
|
|
655
743
|
|
|
656
|
-
* `
|
|
657
|
-
* `
|
|
658
|
-
* `
|
|
744
|
+
* If the `namespace` option is not set:
|
|
745
|
+
* `Stuff::WidgetMapper`
|
|
746
|
+
* `Stuff::ThingMapper`
|
|
747
|
+
* `Stuff::ObjectMapper`
|
|
748
|
+
* `Stuff::BasicObjectMapper`
|
|
749
|
+
* `WidgetMapper`
|
|
750
|
+
* `ThingMapper`
|
|
659
751
|
|
|
660
752
|
If none of these are found an error is raised.
|
|
661
753
|
|
|
@@ -695,10 +787,13 @@ yaks = Yaks.new do
|
|
|
695
787
|
rel_template "http://api.example.com/rel/{rel}"
|
|
696
788
|
end
|
|
697
789
|
|
|
698
|
-
|
|
790
|
+
class MyMapper < Yaks::Mapper
|
|
791
|
+
# rel: "http://api.example.com/rel/widgets"
|
|
792
|
+
has_many :widgets
|
|
699
793
|
|
|
700
|
-
|
|
701
|
-
has_one :widget
|
|
794
|
+
# rel: "http://api.example.com/rel/widget"
|
|
795
|
+
has_one :widget
|
|
796
|
+
end
|
|
702
797
|
```
|
|
703
798
|
|
|
704
799
|
<a id="primitivizer"></a>
|
|
@@ -752,10 +847,10 @@ Yaks::Format.all.each do |format|
|
|
|
752
847
|
end
|
|
753
848
|
|
|
754
849
|
# one time Yaks configuration
|
|
755
|
-
yaks = Yaks.new
|
|
850
|
+
yaks = Yaks.new
|
|
756
851
|
|
|
757
852
|
# on each request
|
|
758
|
-
runner = yaks.runner(
|
|
853
|
+
runner = yaks.runner(post, env: rack_env)
|
|
759
854
|
format = runner.format_name
|
|
760
855
|
output = runner.call
|
|
761
856
|
```
|
|
@@ -763,12 +858,19 @@ output = runner.call
|
|
|
763
858
|
|
|
764
859
|
## Real World Usage
|
|
765
860
|
|
|
766
|
-
Yaks is used in production by
|
|
861
|
+
Yaks is used in production by
|
|
862
|
+
|
|
863
|
+
* [Ticketsolve](http://www.ticketsolve.com/). You can find an example API endpoint [here](http://leicestersquaretheatre.ticketsolve.com/api).
|
|
864
|
+
* Advertile Mobile for their product AppBounty (internal API)
|
|
767
865
|
|
|
768
866
|
## Demo
|
|
769
867
|
|
|
770
868
|
You can find an outdated example app at [Yakports](https://github.com/plexus/yakports), or browse the HAL api directly using the [HAL browser](http://yaks-airports.herokuapp.com/browser.html).
|
|
771
869
|
|
|
870
|
+
## Cookbook
|
|
871
|
+
|
|
872
|
+
See the [cookbook](COOKBOOK.md) for some usage examples taking from a real world app.
|
|
873
|
+
|
|
772
874
|
## Standards Based
|
|
773
875
|
|
|
774
876
|
Yaks is based on internet standards, including
|
|
@@ -781,7 +883,7 @@ Yaks is based on internet standards, including
|
|
|
781
883
|
|
|
782
884
|
## How to contribute
|
|
783
885
|
|
|
784
|
-
Run the tests, the examples, try it with your own stuff and leave your impressions in the issues.
|
|
886
|
+
Run the tests, the examples, try it with your own stuff and leave your impressions in the issues.
|
|
785
887
|
|
|
786
888
|
To fix a bug
|
|
787
889
|
|
data/Rakefile
CHANGED
|
@@ -58,8 +58,6 @@ task :mutant_chunked do
|
|
|
58
58
|
# >> Yaks::Format::Transit::ReadHandler
|
|
59
59
|
# >> Yaks::Format::Transit::WriteHandler
|
|
60
60
|
# >> Yaks::HTML5Forms
|
|
61
|
-
# >> Yaks::Identifier
|
|
62
|
-
# >> Yaks::Identifier::LinkRelation
|
|
63
61
|
# >> Yaks::IllegalStateError
|
|
64
62
|
# >> Yaks::Mapper
|
|
65
63
|
# >> Yaks::Mapper::Association
|
|
@@ -85,7 +83,7 @@ task :mutant_chunked do
|
|
|
85
83
|
# Yaks::Resource::Form::Field,
|
|
86
84
|
# Yaks::Resource::Form::Field::Option,
|
|
87
85
|
# Yaks::Resource::Form::Fieldset,
|
|
88
|
-
#Yaks::Resource::Link,
|
|
86
|
+
# Yaks::Resource::Link,
|
|
89
87
|
Yaks::Resource::HasFields,
|
|
90
88
|
# >> Yaks::Runner
|
|
91
89
|
# >> Yaks::RuntimeError
|
data/ataru_setup.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# "Require your project source code, with the correct path"
|
|
2
|
+
|
|
3
|
+
require "yaks"
|
|
4
|
+
require "hamster"
|
|
5
|
+
|
|
6
|
+
Post = Struct.new(:id, :title, :author, :comments)
|
|
7
|
+
Author = Struct.new(:name)
|
|
8
|
+
|
|
9
|
+
module MyAPI
|
|
10
|
+
Product = Struct.new(:id, :label)
|
|
11
|
+
|
|
12
|
+
class ProductMapper < Yaks::Mapper
|
|
13
|
+
attributes :id, :label
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class AuthorMapper < Yaks::Mapper
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class CommentMapper < Yaks::Mapper
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class PostMapper < Yaks::Mapper
|
|
24
|
+
link :self, '/api/posts/{id}'
|
|
25
|
+
|
|
26
|
+
attributes :id, :title
|
|
27
|
+
|
|
28
|
+
has_one :author
|
|
29
|
+
has_many :comments
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class HomeMapper < Yaks::Mapper; end
|
|
33
|
+
|
|
34
|
+
class SpecialMapper < Yaks::Mapper; end
|
|
35
|
+
|
|
36
|
+
module Setup
|
|
37
|
+
def setup
|
|
38
|
+
# Do some nice setup that is run before every snippet
|
|
39
|
+
# If you'd like to use instance variables define them here, e.g
|
|
40
|
+
# @important_variable_i_will_use_in_my_code_snippets = true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def teardown
|
|
44
|
+
# Do some cleanup that is run after every snippet
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# If you like local variables you can define methods, e.g
|
|
48
|
+
# def number_of_wishes
|
|
49
|
+
# 101
|
|
50
|
+
# end
|
|
51
|
+
|
|
52
|
+
def my_env
|
|
53
|
+
{'something' => true}
|
|
54
|
+
end
|
|
55
|
+
alias_method :rack_env, :my_env
|
|
56
|
+
|
|
57
|
+
def post
|
|
58
|
+
Post.new(7, "Yaks is Al Dente", nil, [])
|
|
59
|
+
end
|
|
60
|
+
alias_method :foo, :post
|
|
61
|
+
|
|
62
|
+
def product
|
|
63
|
+
MyAPI::Product.new(42, "Shiny thing")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# # Tell your web framework about the supported formats
|
|
67
|
+
# Yaks::Format.all.each do |format|
|
|
68
|
+
# mime_type format.format_name, format.media_type
|
|
69
|
+
# end
|
|
70
|
+
def mime_type(*_args)
|
|
71
|
+
end
|
|
72
|
+
end
|