yaks 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://secure.travis-ci.org/plexus/yaks.png?branch=master)][travis]
|
3
3
|
[![Dependency Status](https://gemnasium.com/plexus/yaks.png)][gemnasium]
|
4
4
|
[![Code Climate](https://codeclimate.com/github/plexus/yaks.png)][codeclimate]
|
5
|
+
[![Gitter](https://badges.gitter.im/Join Chat.svg)][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
|