yaks 0.8.2 → 0.8.3
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 +124 -9
- data/lib/yaks/default_policy.rb +9 -1
- data/lib/yaks/version.rb +1 -1
- data/spec/support/classes_for_policy_testing.rb +9 -1
- data/spec/unit/yaks/default_policy/derive_mapper_from_object_spec.rb +16 -0
- data/yaks.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a609ab5341e17172a098a296e8935d9abf4fa995
|
4
|
+
data.tar.gz: 44f4ef2d6d7786bf09261b352ed9e253064ff31e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f65c4f9d62853543fc92fbe58fc9a3c4b057eac27473a951d8cfe38edf19cf0af461bd9e047e20cbce47ab771ded553b859937e6c8dff7e1a25aa2f1101f8a18
|
7
|
+
data.tar.gz: be7d5c1edcc4e745a25897deae315000d1bdff1713b8a6d61876f36d62d4dc866792a5f362957c7218e64e7a9c346bec38bd064e7297cfa33be26702b451bd33
|
data/README.md
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
[][travis]
|
3
3
|
[][gemnasium]
|
4
4
|
[][codeclimate]
|
5
|
+
[][gitter]
|
5
6
|
|
6
7
|
[gem]: https://rubygems.org/gems/yaks
|
7
8
|
[travis]: https://travis-ci.org/plexus/yaks
|
8
9
|
[gemnasium]: https://gemnasium.com/plexus/yaks
|
9
10
|
[codeclimate]: https://codeclimate.com/github/plexus/yaks
|
11
|
+
[gitter]: https://gitter.im/plexus/yaks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
10
12
|
|
11
13
|
# Yaks
|
12
14
|
|
@@ -22,6 +24,7 @@ requested. These formats are presently supported:
|
|
22
24
|
* Collection+JSON
|
23
25
|
* HTML
|
24
26
|
* HALO
|
27
|
+
* Transit
|
25
28
|
|
26
29
|
## State of Development
|
27
30
|
|
@@ -309,9 +312,15 @@ If `env` contains a `HTTP_ACCEPT` key (Rack's way of representing the
|
|
309
312
|
`Accept` header), Yaks will return the format that most closely
|
310
313
|
matches what was requested.
|
311
314
|
|
315
|
+
<a id="namespace"></a>
|
316
|
+
|
312
317
|
## Namespace
|
313
318
|
|
314
|
-
Yaks by default will find your mappers for you if they follow the
|
319
|
+
Yaks by default will find your mappers for you if they follow the
|
320
|
+
naming convention of appending 'Mapper' to the model class name. This
|
321
|
+
(and all other "conventions") can be easily redefined though, see the
|
322
|
+
<a href="#policy">policy</a> section. If you have your mappers inside a
|
323
|
+
module, use `namespace`.
|
315
324
|
|
316
325
|
```ruby
|
317
326
|
module API
|
@@ -327,7 +336,8 @@ yaks = Yaks.new do
|
|
327
336
|
end
|
328
337
|
```
|
329
338
|
|
330
|
-
If your namespace contains a `CollectionMapper`, Yaks will use that
|
339
|
+
If your namespace contains a `CollectionMapper`, Yaks will use that
|
340
|
+
instead of `Yaks::CollectionMapper`, e.g.
|
331
341
|
|
332
342
|
```ruby
|
333
343
|
module API
|
@@ -339,7 +349,8 @@ module API
|
|
339
349
|
end
|
340
350
|
```
|
341
351
|
|
342
|
-
You can also have collection mappers based on the type of members the
|
352
|
+
You can also have collection mappers based on the type of members the
|
353
|
+
collection holds, e.g.
|
343
354
|
|
344
355
|
```ruby
|
345
356
|
module API
|
@@ -358,12 +369,20 @@ module API
|
|
358
369
|
end
|
359
370
|
```
|
360
371
|
|
361
|
-
Yaks will automatically detect and use this collection when
|
372
|
+
Yaks will automatically detect and use this collection when
|
373
|
+
serializing an array of `LineItem` objects. See <a
|
374
|
+
href="#derive_mapper_from_object">derive_mapper_from_object</a> for
|
375
|
+
details.
|
362
376
|
|
363
377
|
|
364
378
|
## Custom attribute/link/subresource handling
|
365
379
|
|
366
|
-
When inheriting from `Yaks::Mapper`, you can override
|
380
|
+
When inheriting from `Yaks::Mapper`, you can override
|
381
|
+
`map_attributes`, `map_links` and `map_resources` to skip (or augment)
|
382
|
+
above methods, and instead implement your own custom mechanism. These
|
383
|
+
methods take a `Yaks::Resource` instance, and should return an updated
|
384
|
+
resource. They should not alter the resource instance in-place. For
|
385
|
+
example
|
367
386
|
|
368
387
|
```ruby
|
369
388
|
class ErrorMapper < Yaks::Mapper
|
@@ -441,6 +460,9 @@ HAL. To stick close to the spec you're best to create your own
|
|
441
460
|
singular types that represent collections, rather than rendering a top
|
442
461
|
level CollectionResource.
|
443
462
|
|
463
|
+
Yaks also has a derived format called HALO, which is a non-standard
|
464
|
+
extension to HAL which includes form elements.
|
465
|
+
|
444
466
|
### HTML
|
445
467
|
|
446
468
|
The hypermedia format *par excellence*. Yaks can generate a version of
|
@@ -511,11 +533,20 @@ class PostMapper < Yaks::Mapper
|
|
511
533
|
end
|
512
534
|
```
|
513
535
|
|
514
|
-
Subresources aren't mapped because Collection+JSON doesn't really have
|
536
|
+
Subresources aren't mapped because Collection+JSON doesn't really have
|
537
|
+
that concept.
|
538
|
+
|
539
|
+
### Transit
|
540
|
+
|
541
|
+
There is experimental support for Transit. The transit gem handles
|
542
|
+
serialization internally, so there is no intermediate document. The
|
543
|
+
`format` step already returns the serialized string.
|
515
544
|
|
516
545
|
## Hooks
|
517
546
|
|
518
|
-
It is possible to hook into the Yaks pipeline to perform extra
|
547
|
+
It is possible to hook into the Yaks pipeline to perform extra
|
548
|
+
processing steps before, after, or around each step. It also possible
|
549
|
+
to skip a step.
|
519
550
|
|
520
551
|
``` ruby
|
521
552
|
yaks = Yaks.new do
|
@@ -530,6 +561,8 @@ yaks = Yaks.new do
|
|
530
561
|
end
|
531
562
|
```
|
532
563
|
|
564
|
+
<a id="policy"></a>
|
565
|
+
|
533
566
|
## Policy over Configuration
|
534
567
|
|
535
568
|
It's an old adage in the Ruby/Rails world to have "Convention over Configuration", mostly to derive values that were not given explicitly. Typically based on things having similar names and a 1-1 derivable relationship.
|
@@ -574,7 +607,89 @@ yaks = Yaks.new do
|
|
574
607
|
end
|
575
608
|
```
|
576
609
|
|
577
|
-
<a id="
|
610
|
+
<a id="derive_mapper_from_object"></a>
|
611
|
+
|
612
|
+
### derive_mapper_from_object
|
613
|
+
|
614
|
+
This is called when trying to serialize something and no explicit
|
615
|
+
mapper is given. To recap, it's always possible to be explicit, e.g.
|
616
|
+
|
617
|
+
```
|
618
|
+
yaks.call(widget, mapper: WidgetMapper)
|
619
|
+
yaks.call(array_of_widgets, mapper: MyCollectionMapper, item_mapper: WidgetMapper)
|
620
|
+
```
|
621
|
+
|
622
|
+
If the mapper is left unspecified, Yaks will inspect whatever you pass
|
623
|
+
it, and try various constant lookups based on naming. These all happen
|
624
|
+
in the configured namespace, which defaults to the Ruby top level.
|
625
|
+
|
626
|
+
If the object responds to `to_ary` it is considered a collection. If
|
627
|
+
the first object in the collection has a class of `Widget`, and the
|
628
|
+
configured namespace is `API`, then these are tried in turn
|
629
|
+
|
630
|
+
* `API::WidgetCollectionMapper`
|
631
|
+
* `API::CollectionMapper`
|
632
|
+
* `Yaks::CollectionMapper`
|
633
|
+
|
634
|
+
Note that Yaks can only find a specific collection mapper for a type
|
635
|
+
if the collection passed to Yaks contains at least one element. If
|
636
|
+
it's important that empty collections are handled by the right mapper
|
637
|
+
(e.g. to set a specific `self` or `profile` link), then you have to be
|
638
|
+
explicit.
|
639
|
+
|
640
|
+
If the object is not a collection, then lookup happens based on the
|
641
|
+
class name, and will traverse up the class hierarchy if no suitable
|
642
|
+
mapper is found. So for a `class Widget < Thing`, yaks would look for
|
643
|
+
|
644
|
+
* `API::WidgetMapper`
|
645
|
+
* `API::ThingMapper`
|
646
|
+
* `API::ObjectMapper`
|
647
|
+
|
648
|
+
If none of these are found an error is raised.
|
649
|
+
|
650
|
+
### derive_mapper_from_association
|
651
|
+
|
652
|
+
When no mapper is specified for an association, then this method is
|
653
|
+
called to find the right mapper, based on the association name. In
|
654
|
+
case of `has_many` collections this is the "item mapper", the
|
655
|
+
collection mapper is resolved using `derive_mapper_from_object`.
|
656
|
+
|
657
|
+
By default the mapper class is derived from the name of the association, e.g.
|
658
|
+
|
659
|
+
```
|
660
|
+
has_many :widgets #=> WidgetMapper
|
661
|
+
has_one :widget #=> WidgetMapper
|
662
|
+
```
|
663
|
+
|
664
|
+
It is always possible to explicitly set a mapper.
|
665
|
+
|
666
|
+
```
|
667
|
+
has_one :widget, mapper: FooMapper
|
668
|
+
has_many :widgets, collection_mapper: MyCollectionMapper, mapper: FooMapper
|
669
|
+
```
|
670
|
+
|
671
|
+
### derive_rel_from_association
|
672
|
+
|
673
|
+
Associations have a "rel", an IANA registered identifier or fully
|
674
|
+
qualified URI, that specifies how the object relates to the parent
|
675
|
+
document.
|
676
|
+
|
677
|
+
When configuring Yaks one can set a `rel_template`, that will be used
|
678
|
+
to generate these rels if not explicitly given. The `rel` placeholder
|
679
|
+
in the template will be substituted with the association name.
|
680
|
+
|
681
|
+
``` ruby
|
682
|
+
yaks = Yaks.new do
|
683
|
+
rel_template "http://api.example.com/rel/{rel}"
|
684
|
+
end
|
685
|
+
|
686
|
+
# ... mapper
|
687
|
+
|
688
|
+
has_many :widgets #=> rel: "http://api.example.com/rel/widgets"
|
689
|
+
has_one :widget #=> rel: "http://api.example.com/rel/widget"
|
690
|
+
```
|
691
|
+
|
692
|
+
<a id="primitivizer"></a>
|
578
693
|
|
579
694
|
## Primitivizer
|
580
695
|
|
@@ -603,7 +718,7 @@ end
|
|
603
718
|
Yaks by default "primitivizes" symbols (as strings), and classes that include Enumerable (as arrays).
|
604
719
|
|
605
720
|
|
606
|
-
<a id="integration">
|
721
|
+
<a id="integration"></a>
|
607
722
|
|
608
723
|
## Integration
|
609
724
|
|
data/lib/yaks/default_policy.rb
CHANGED
@@ -36,8 +36,16 @@ module Yaks
|
|
36
36
|
end
|
37
37
|
CollectionMapper
|
38
38
|
else
|
39
|
+
klass = model.class
|
40
|
+
begin
|
41
|
+
name = klass.name.split('::').last
|
42
|
+
return @options[:namespace].const_get(name + 'Mapper')
|
43
|
+
rescue NameError
|
44
|
+
klass = klass.superclass
|
45
|
+
retry if klass
|
46
|
+
end
|
39
47
|
name = model.class.name.split('::').last
|
40
|
-
|
48
|
+
raise "Failed to find a mapper for #{model.inspect}. Did you mean to implement #{name}Mapper?"
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
data/lib/yaks/version.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# Used by Yaks::DefaultPolicy* tests to test various name inference schemes
|
2
2
|
|
3
3
|
class SoyMapper ; end
|
4
|
-
class
|
4
|
+
class Bean ; end
|
5
|
+
class Soy < Bean; end
|
5
6
|
class Wheat ; end
|
6
7
|
|
7
8
|
module MyMappers
|
8
9
|
class SoyMapper ; end
|
10
|
+
class BeanMapper ; end
|
9
11
|
end
|
10
12
|
|
11
13
|
class SoyCollectionMapper ; end
|
@@ -13,6 +15,12 @@ class SoyCollectionMapper ; end
|
|
13
15
|
module Namespace
|
14
16
|
module Nested
|
15
17
|
class Rye ; end
|
18
|
+
class Mung < Bean
|
19
|
+
alias inspect to_s # on 1.9 inspect calls to_s
|
20
|
+
def to_s
|
21
|
+
"mungbean"
|
22
|
+
end
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
26
|
class RyeMapper ; end
|
@@ -75,4 +75,20 @@ RSpec.describe Yaks::DefaultPolicy, '#derive_mapper_from_object' do
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
context 'when a mapper exists for a superclass' do
|
79
|
+
let(:options) { {namespace: MyMappers} }
|
80
|
+
|
81
|
+
it 'should use the superclass mapper' do
|
82
|
+
expect(policy.derive_mapper_from_object(Namespace::Nested::Mung.new)).to be(MyMappers::BeanMapper)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when no mapper is found' do
|
87
|
+
it 'should give a nice message' do
|
88
|
+
expect {
|
89
|
+
policy.derive_mapper_from_object(Namespace::Nested::Mung.new)
|
90
|
+
}.to raise_error /Failed to find a mapper for #<Namespace::Nested::Mung:0x\h+>. Did you mean to implement MungMapper\?/
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
78
94
|
end
|
data/yaks.gemspec
CHANGED
@@ -34,8 +34,8 @@ Gem::Specification.new do |gem|
|
|
34
34
|
gem.add_development_dependency 'bogus'
|
35
35
|
gem.add_development_dependency 'rake'
|
36
36
|
gem.add_development_dependency 'yard'
|
37
|
-
gem.add_development_dependency 'mutant-rspec'
|
38
|
-
gem.add_development_dependency 'mutant'
|
37
|
+
gem.add_development_dependency 'mutant-rspec' if RUBY_VERSION > '1.9'
|
38
|
+
gem.add_development_dependency 'mutant' if RUBY_VERSION > '1.9'
|
39
39
|
gem.add_development_dependency 'rspec-its'
|
40
40
|
gem.add_development_dependency 'benchmark-ips'
|
41
41
|
gem.add_development_dependency 'yaks-html'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yaks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arne Brasseur
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inflection
|