yaks 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +158 -56
  3. data/Rakefile +1 -3
  4. data/ataru_setup.rb +72 -0
  5. data/find_missing_tests.rb +34 -0
  6. data/lib/yaks.rb +8 -10
  7. data/lib/yaks/breaking_changes.rb +4 -6
  8. data/lib/yaks/builder.rb +1 -1
  9. data/lib/yaks/changelog.rb +1 -1
  10. data/lib/yaks/collection_mapper.rb +8 -5
  11. data/lib/yaks/collection_resource.rb +0 -1
  12. data/lib/yaks/config.rb +17 -7
  13. data/lib/yaks/configurable.rb +20 -14
  14. data/lib/yaks/default_policy.rb +82 -33
  15. data/lib/yaks/format.rb +7 -3
  16. data/lib/yaks/format/collection_json.rb +4 -4
  17. data/lib/yaks/format/hal.rb +1 -2
  18. data/lib/yaks/format/halo.rb +2 -4
  19. data/lib/yaks/format/json_api.rb +46 -27
  20. data/lib/yaks/html5_forms.rb +0 -2
  21. data/lib/yaks/mapper.rb +5 -5
  22. data/lib/yaks/mapper/association.rb +7 -7
  23. data/lib/yaks/mapper/association_mapper.rb +2 -0
  24. data/lib/yaks/mapper/attribute.rb +10 -4
  25. data/lib/yaks/mapper/config.rb +2 -2
  26. data/lib/yaks/mapper/form.rb +4 -10
  27. data/lib/yaks/mapper/form/config.rb +16 -17
  28. data/lib/yaks/mapper/form/dynamic_field.rb +1 -1
  29. data/lib/yaks/mapper/form/field.rb +16 -7
  30. data/lib/yaks/mapper/form/field/option.rb +5 -4
  31. data/lib/yaks/mapper/form/fieldset.rb +1 -1
  32. data/lib/yaks/mapper/form/legend.rb +18 -0
  33. data/lib/yaks/mapper/has_many.rb +1 -0
  34. data/lib/yaks/mapper/link.rb +7 -4
  35. data/lib/yaks/null_resource.rb +4 -5
  36. data/lib/yaks/pipeline.rb +2 -2
  37. data/lib/yaks/primitivize.rb +3 -2
  38. data/lib/yaks/reader/hal.rb +12 -13
  39. data/lib/yaks/reader/json_api.rb +50 -33
  40. data/lib/yaks/resource.rb +6 -7
  41. data/lib/yaks/resource/form.rb +2 -12
  42. data/lib/yaks/resource/form/field.rb +4 -3
  43. data/lib/yaks/resource/form/field/option.rb +1 -1
  44. data/lib/yaks/resource/form/fieldset.rb +1 -1
  45. data/lib/yaks/resource/form/legend.rb +18 -0
  46. data/lib/yaks/resource/has_fields.rb +13 -7
  47. data/lib/yaks/resource/link.rb +1 -1
  48. data/lib/yaks/runner.rb +5 -2
  49. data/lib/yaks/serializer.rb +2 -3
  50. data/lib/yaks/util.rb +7 -8
  51. data/lib/yaks/version.rb +1 -1
  52. data/spec/acceptance/acceptance_spec.rb +53 -38
  53. data/spec/acceptance/json_shared_examples.rb +45 -12
  54. data/spec/acceptance/models.rb +1 -1
  55. data/spec/integration/dynamic_form_fields_spec.rb +0 -1
  56. data/spec/integration/fieldset_spec.rb +18 -20
  57. data/spec/integration/map_to_resource_spec.rb +6 -6
  58. data/spec/json/{confucius.collection.json → confucius.collection_json.json} +0 -0
  59. data/spec/json/confucius.json_api.json +43 -27
  60. data/spec/json/list_of_quotes.collection_json.json +43 -0
  61. data/spec/json/list_of_quotes.hal.json +18 -0
  62. data/spec/json/list_of_quotes.json_api.json +25 -0
  63. data/spec/json/youtypeitwepostit.collection_json.json +45 -0
  64. data/spec/spec_helper.rb +4 -3
  65. data/spec/support/classes_for_policy_testing.rb +38 -14
  66. data/spec/support/deep_eql.rb +21 -18
  67. data/spec/support/pet_mapper.rb +2 -0
  68. data/spec/support/shared_contexts.rb +9 -9
  69. data/spec/unit/yaks/builder_spec.rb +41 -18
  70. data/spec/unit/yaks/collection_mapper_spec.rb +22 -19
  71. data/spec/unit/yaks/collection_resource_spec.rb +16 -8
  72. data/spec/unit/yaks/config_spec.rb +215 -19
  73. data/spec/unit/yaks/configurable_spec.rb +66 -7
  74. data/spec/unit/yaks/default_policy/derive_mapper_from_collection_spec.rb +47 -0
  75. data/spec/unit/yaks/default_policy/derive_mapper_from_item_spec.rb +114 -0
  76. data/spec/unit/yaks/default_policy/derive_mapper_from_object_spec.rb +29 -71
  77. data/spec/unit/yaks/default_policy_spec.rb +4 -5
  78. data/spec/unit/yaks/format/collection_json_spec.rb +35 -36
  79. data/spec/unit/yaks/format/hal_spec.rb +3 -3
  80. data/spec/unit/yaks/format/json_api_spec.rb +109 -68
  81. data/spec/unit/yaks/format_spec.rb +34 -0
  82. data/spec/unit/yaks/fp/callable_spec.rb +5 -3
  83. data/spec/unit/yaks/mapper/association_mapper_spec.rb +22 -4
  84. data/spec/unit/yaks/mapper/association_spec.rb +23 -11
  85. data/spec/unit/yaks/mapper/attribute_spec.rb +46 -7
  86. data/spec/unit/yaks/mapper/config_spec.rb +2 -3
  87. data/spec/unit/yaks/mapper/form/config_spec.rb +95 -0
  88. data/spec/unit/yaks/mapper/form/dynamic_field_spec.rb +30 -0
  89. data/spec/unit/yaks/mapper/form/field/option_spec.rb +48 -4
  90. data/spec/unit/yaks/mapper/form/field_spec.rb +43 -2
  91. data/spec/unit/yaks/mapper/form/fieldset_spec.rb +67 -8
  92. data/spec/unit/yaks/mapper/form/legend_spec.rb +52 -0
  93. data/spec/unit/yaks/mapper/form_spec.rb +84 -23
  94. data/spec/unit/yaks/mapper/has_many_spec.rb +39 -36
  95. data/spec/unit/yaks/mapper/has_one_spec.rb +28 -20
  96. data/spec/unit/yaks/mapper/link_spec.rb +68 -16
  97. data/spec/unit/yaks/mapper_spec.rb +118 -30
  98. data/spec/unit/yaks/null_resource_spec.rb +83 -52
  99. data/spec/unit/yaks/pipeline_spec.rb +101 -74
  100. data/spec/unit/yaks/primitivize_spec.rb +25 -6
  101. data/spec/unit/yaks/resource/form/field_spec.rb +5 -5
  102. data/spec/unit/yaks/resource/form/fieldset_spec.rb +7 -0
  103. data/spec/unit/yaks/resource/form/legend_spec.rb +8 -0
  104. data/spec/unit/yaks/resource/form_spec.rb +17 -37
  105. data/spec/unit/yaks/resource/has_fields_spec.rb +44 -3
  106. data/spec/unit/yaks/resource/link_spec.rb +11 -6
  107. data/spec/unit/yaks/resource_spec.rb +87 -98
  108. data/spec/unit/yaks/runner_spec.rb +112 -28
  109. data/spec/unit/yaks/serializer_spec.rb +1 -1
  110. data/spec/unit/yaks/util_spec.rb +30 -10
  111. data/spec/yaml/list_of_quotes.yaml +13 -0
  112. data/yaks.gemspec +21 -13
  113. metadata +129 -41
  114. data/lib/yaks/attributes.rb +0 -86
  115. data/lib/yaks/fp.rb +0 -26
  116. data/lib/yaks/identifier/link_relation.rb +0 -17
  117. data/resources/iana-link-relations.csv +0 -152
  118. data/spec/json/youtypeitwepostit.collection.json +0 -45
  119. data/spec/unit/yaks/attributes_spec.rb +0 -178
  120. data/spec/unit/yaks/fp_spec.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e1351b2c236dc9fb68ff5bbe9c365f7addb38cad
4
- data.tar.gz: d8baafb1e55bc4bf5e926e012dac9bd20d7284f8
3
+ metadata.gz: 8e26f0f65962ea64eee11346ede1401347525188
4
+ data.tar.gz: 40881b570c5b8145e79a92251a35275b62da9994
5
5
  SHA512:
6
- metadata.gz: 4f5732d430846954a651d3aff1145cf07610098d23c0ba2b28bfe7626b3e3c2c3c741d6f50d84459360a1986d820f10604d115bd3336ccad6dac2386bf808142
7
- data.tar.gz: 7ce7ea4c6bdf3c0e0fc2ae11ecee61813c4be3b8eefe01316153ba427d6522496f2d92e3efcbf2c29f60bea9db3a93b158caf4d667472835438c284ae14df08f
6
+ metadata.gz: 9b4370186b9d44d56404df20e65bfb58bedd666b6bd5be2cb78684d1022ed74bb2df1a01c6381dc743c9769cadbdc3fcff441d52298108137a4fe60f873c2dab
7
+ data.tar.gz: 340ea7d369824f9ac7d0ea98e0995c0d4192b63c6a66f9faff2033b78b7b281d494c9044508c7a9bdd085e8a20ffb76b89a54716aef447c8824a27d3080a37ff
data/README.md CHANGED
@@ -1,21 +1,21 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/yaks.png)][gem]
2
2
  [![Build Status](https://secure.travis-ci.org/plexus/yaks.png?branch=master)][travis]
3
- [![Dependency Status](https://gemnasium.com/plexus/yaks.png)][gemnasium]
4
3
  [![Code Climate](https://codeclimate.com/github/plexus/yaks.png)][codeclimate]
5
4
  [![Gitter](https://badges.gitter.im/Join Chat.svg)][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
- ![](logo.png)
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
- ## State of Development
37
-
38
- This library came into existence because we at
39
- [Ticketsolve](http://www.ticketsolve.com) wanted to build a rich
40
- hypermedia API, and were dissatisfied with any of the existing Ruby
41
- solutions at the time (November 2013).
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
- We are still actively expanding our API, and with that Yaks continues
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
- Yaks can be used in production today, as we do, but until 1.0 is
48
- released there will regularly be breaking changes, as we figure out
49
- the best way to do things. These are all documented clearly in the
50
- [changelog](/CHANGELOG.md).
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
- namespace ::MyAPI
89
+ mapper_namespace ::MyAPI
63
90
  json_serializer do |data|
64
- MultiJson.dump(data)
91
+ JSON.dump(data)
65
92
  end
66
93
  end
67
94
 
68
- yaks.call(data) # => '{"foo": "bar", "_links": { ... }}'
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 method 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.
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 :id, :body, :date
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 < BaseMapper
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
- yaks = Yaks.new
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 `namespace`.
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
- namespace API::Mappers
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
- default_format :json_api
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
- key :pet
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
- default_format :collection_json
562
+ Yaks.new do
563
+ default_format :collection_json
532
564
 
533
- collection_json = Yaks.new do
534
- format_options :collection_json, template: :my_template_form
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
- policy MyPolicy
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, and try various constant lookups based on naming. These all happen
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 responds to `to_ary` it is considered a collection. If
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
- If the object is not a collection, then lookup happens based on the
653
- class name, and will traverse up the class hierarchy if no suitable
654
- mapper is found. So for a `class Widget < Thing`, yaks would look for
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
- * `API::WidgetMapper`
657
- * `API::ThingMapper`
658
- * `API::ObjectMapper`
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
- # ... mapper
790
+ class MyMapper < Yaks::Mapper
791
+ # rel: "http://api.example.com/rel/widgets"
792
+ has_many :widgets
699
793
 
700
- has_many :widgets #=> rel: "http://api.example.com/rel/widgets"
701
- has_one :widget #=> rel: "http://api.example.com/rel/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(object, env: rack_env)
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 [Ticketsolve](http://www.ticketsolve.com/). You can find an example API endpoint [here](http://leicestersquaretheatre.ticketsolve.com/api).
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. Or discuss on [API-craft](https://groups.google.com/d/forum/api-craft).
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