munson 0.2.0 → 0.3.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
  SHA1:
3
- metadata.gz: 58f61fc4c3adf530a74a67fe73b0c1907e097a3a
4
- data.tar.gz: c0dfb862271eee803921d1a9772514de40f8d669
3
+ metadata.gz: 123416f906ed71b0bdc64d573de72e080c3e96ca
4
+ data.tar.gz: 2b29a00a7dc9417caa47588af57f05fe448d99a7
5
5
  SHA512:
6
- metadata.gz: 59c16ff0e3445ebdc0f9adc4b422537714e0767a0a780533f2b682a08ce1ce2de0cf3af0cb88672c2b2d7fa96dc7a781a42692665f9e832033480f90fbbcf0ec
7
- data.tar.gz: fae8f69311ed2cbec3efc7397c8c2c8c01165b0c493b77e4f4c80805c07aee9b0fb798cbbf8dee8b2d06af3dcf70dd803bd4f74323081460ead7e294f9b4ea4c
6
+ metadata.gz: 53729cc19c386163266f1ee7a13bf4a508f76c757d465410739076525b9cc0b9030710b057e0d198bcb358a74a7e939803fa6e1541acaf6df10a58fb46f2a0d8
7
+ data.tar.gz: 3cf86622c38ee8673daf552033f0aac2cff89a1e40ddd3f6c122bcae58e60f7c947592c6348848e24d3634fcda3f0a848978cc45b3d2d9e334e71eda6dc07226
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [![Code Climate](https://codeclimate.com/github/coryodaniel/munson/badges/gpa.svg)](https://codeclimate.com/github/coryodaniel/munson)
4
4
  [![Test Coverage](https://codeclimate.com/github/coryodaniel/munson/badges/coverage.svg)](https://codeclimate.com/github/coryodaniel/munson/coverage)
5
- ![Build Status](https://travis-ci.org/coryodaniel/munson.svg?branch=master)
5
+ ![Build Status](https://travis-ci.org/stacksocial/munson.svg?branch=master)
6
6
 
7
- A JSON API Spec client for Ruby
7
+ A JSON API client for Ruby
8
8
 
9
9
  ## Installation
10
10
 
@@ -22,116 +22,103 @@ Or install it yourself as:
22
22
 
23
23
  $ gem install munson
24
24
 
25
- ## Usage
26
-
27
- ### Munson::Connection and configuring the default connection
28
-
29
- Munson is designed to support multiple connections or API endpoints. A connection is a wrapper around Faraday::Connection that includes a few pieces of middleware for parsing and encoding requests and responses to JSON API Spec.
25
+ ## Basic Usage
30
26
 
31
27
  ```ruby
32
- Munson.configure(url: 'http://api.example.com') do |c|
33
- c.use MyCustomMiddleware
34
- end
35
- ```
36
-
37
- Options can be any [Faraday::Connection options](https://github.com/lostisland/faraday/blob/master/lib/faraday/connection.rb Faraday::Connection)
28
+ class Article < Munson::Resource
29
+ # This is done automatically if the tableize method is present
30
+ self.type = :articles
38
31
 
39
- Additional connections can be created with:
40
- ```ruby
41
- my_connection = Munson::Connection.new(url: 'http://api2.example.com') do |c|
42
- c.use MoreMiddleware
43
- c.use AllTheMiddlewares
32
+ # how to process the JSON API ID. JSON API always uses strings, but Munson defaults to :integer
33
+ key_type :integer, #:string, ->(id){ }
34
+ attribute :title, :string
44
35
  end
45
36
  ```
46
37
 
47
- ### Munson::Agent
38
+ ### Registering the JSONAPI 'type'
48
39
 
49
- Munson::Agent provides a small 'DSL' to build requests and parse responses,
50
- while allowing additional configuration for a particular 'resource.'
40
+ Calling ```Article.type = :articles``` registers the class ```Article``` as the handler for JSON API resources of the type ```articles```.
51
41
 
42
+ When the ActiveSupport method ```tableize``` is present, this will be set automatically. A class can be bound to multiple types:
52
43
 
53
44
  ```ruby
54
- Munson.configure url: 'http://api.example.com'
55
-
56
- class Product
57
- def self.munson
58
- return @munson if @munson
59
- @munson = Munson::Agent.new(
60
- connection: Munson.default_connection, # || Munson::Connection.new(...)
61
- paginator: :offset,
62
- type: 'products'
63
- )
64
- end
65
- end
45
+ Article.type = :articles
46
+ Munson.register_type(:posts, Article)
66
47
  ```
67
48
 
68
- #### Getting the faraday response
49
+ ### Querying
69
50
  ```ruby
70
- query = Product.munson.filter(min_price: 30, max_price: 65)
71
- # its chainable
72
- query.filter(category: 'Hats').filter(size: ['small', 'medium'])
51
+ articles = Article.fetch # Get some articles
52
+ article = Article.find(9) # Find an article
73
53
 
74
- query.to_params
75
- #=> {:filter=>{:min_price=>"30", :max_price=>"65", :category=>"Hats", :size=>"small,medium"}}
54
+ query = Article.fields(:title).include(:author, :comments).sort(id: :desc).filter(published: true)
55
+ query.to_params #=> {:filter=>{:published=>"true"}, :fields=>{:articles=>"title"}, :include=>"author,comments", :sort=>"-id"}
56
+ query.to_query_string #=> "fields[articles]=title&filter[published]=true&include=author,comments&sort=-id"
76
57
 
77
- Product.munson.get(params: query.to_params)
58
+ query.fetch # Fetch articles w/ the given query string
78
59
  ```
79
60
 
61
+ The Munson::Resource delegates a few methods to its underlying Munson::Connection:
62
+
80
63
  #### Filtering
81
64
 
82
65
  ```ruby
83
- query = Product.munson.filter(min_price: 30, max_price: 65)
66
+ query = Product.filter(min_price: 30, max_price: 65)
67
+
84
68
  # its chainable
85
69
  query.filter(category: 'Hats').filter(size: ['small', 'medium'])
86
70
 
87
71
  query.to_params
88
72
  #=> {:filter=>{:min_price=>"30", :max_price=>"65", :category=>"Hats", :size=>"small,medium"}}
89
73
 
90
- query.fetch #=> Some lovely data
74
+ query.fetch #=> Munson::Collection<Product,Product>
91
75
  ```
92
76
 
93
77
  #### Sorting
94
78
 
95
79
  ```ruby
96
- query = Product.munson.sort(created_at: :desc)
80
+ query = Product.sort(created_at: :desc)
81
+
97
82
  # its chainable
98
83
  query.sort(:price) # defaults to ASC
99
84
 
100
85
  query.to_params
101
86
  #=> {:sort=>"-created_at,price"}
102
87
 
103
- query.fetch #=> Some lovely data
88
+ query.fetch #=> Munson::Collection<Product,Product>
104
89
  ```
105
90
 
106
91
  #### Including (Side loading related resources)
107
92
 
108
93
  ```ruby
109
- query = Product.munson.includes(:manufacturer)
94
+ query = Product.include(:manufacturer)
95
+
110
96
  # its chainable
111
- query.includes(:vendor)
97
+ query.include(:vendor)
112
98
 
113
99
  query.to_params
114
100
  #=> {:include=>"manufacturer,vendor"}
115
101
 
116
- query.fetch #=> Some lovely data
102
+ query.fetch #=> Munson::Collection<Product,Product>
117
103
  ```
118
104
 
119
105
  #### Sparse Fieldsets
120
106
 
121
107
  ```ruby
122
- query = Product.munson.fields(products: [:name, :price])
108
+ query = Product.fields(products: [:name, :price])
109
+
123
110
  # its chainable
124
- query.includes(:manufacturer).fields(manufacturer: [:name])
111
+ query.include(:manufacturer).fields(manufacturer: [:name])
125
112
 
126
113
  query.to_params
127
114
  #=> {:fields=>{:products=>"name,price", :manufacturer=>"name"}, :include=>"manufacturer"}
128
115
 
129
- query.fetch #=> Some lovely data
116
+ query.fetch #=> Munson::Collection<Product,Product>
130
117
  ```
131
118
 
132
119
  #### All the things!
133
120
  ```ruby
134
- query = Product.munson.
121
+ query = Product.
135
122
  filter(min_price: 30, max_price: 65).
136
123
  includes(:manufacturer).
137
124
  sort(popularity: :desc, price: :asc).
@@ -139,228 +126,264 @@ query = Product.munson.
139
126
  page(number: 1, limit: 100)
140
127
 
141
128
  query.to_params
129
+
142
130
  #=> {:filter=>{:min_price=>"30", :max_price=>"65"}, :fields=>{:product=>"name,price", :manufacturer=>"name,website"}, :include=>"manufacturer", :sort=>"-popularity,price", :page=>{:limit=>10}}
143
131
 
144
- query.fetch #=> Some lovely data
132
+ query.fetch #=> Munson::Collection<Product,Product>
145
133
  ```
146
134
 
147
135
  #### Fetching a single resource
148
136
 
149
137
  ```ruby
150
- Product.munson.find(1)
138
+ Product.find(1) #=> product
151
139
  ```
152
140
 
153
- #### Paginating
141
+ ### Accessing Munson internals
142
+ Every Munson::Resource has an internally managed client. It is accessible via ```.munson```
154
143
 
155
- A paged and offset paginator are included with Munson.
156
-
157
- Using the ```offset``` paginator
158
144
  ```ruby
159
- class Product
160
- def self.munson
161
- return @munson if @munson
162
- @munson = Munson::Agent.new(
163
- paginator: :offset,
164
- type: 'products'
165
- )
166
- end
167
- end
168
-
169
- query = Product.munson.includes('manufacturer').page(offset: 10, limit: 25)
170
- query.to_params
171
- # => {:include=>"manufacturer", :page=>{:limit=>10, :offset=>10}}
172
-
173
- query.fetch #=> Some lovely data
145
+ Article.munson #=> Munson::Client
146
+ Article.munson.path #=> base path to use for this resource. Defaults to "/" + type; i.e., "/articles"
147
+ Article.munson.agent #=> Munson::Agent: the agent wraps the Munson::Connection. It performs the low level GET/POST/PUT/PATCH/DELETE methods
148
+ Article.munson.query #=> Munson::Query: a chainable query building instance
149
+ Article.munson.connection #=> Munson::Connection: Small wrapper around the Farady connection
150
+ Article.munson.connection.response_key_format #=> :dasherize, :camelize, nil
151
+ Article.munson.connection.url #=> This endpoints base URL http://api.example.com/
152
+ Article.munson.connection.faraday #=> The faraday object for this connection
153
+ Article.muson.connection = SomeNewConnectionYouPrefer
154
+ Article.munson.connection.configure(opts) do { |faraday_conn| } #=> Feel free to reconfigure me ;D
174
155
  ```
175
156
 
176
- Using the ```paged``` paginator
157
+ ### Persistence Resources
177
158
  ```ruby
178
- class Product
179
- def self.munson
180
- return @munson if @munson
181
- @munson = Munson::Agent.new(
182
- paginator: :paged,
183
- type: 'products'
184
- )
185
- end
159
+ class Article < Munson::Resource
160
+ attribute :title, :string
161
+ attribute :body, :string
162
+ attribute :created_at, :time
186
163
  end
164
+ ```
187
165
 
188
- query = Product.munson.includes('manufacturer').page(page: 10, size: 25)
189
- query.to_params
190
- # => {:include=>"manufacturer", :page=>{:page=>10, :size=>10}}
166
+ Creating a new resource
191
167
 
192
- query.fetch #=> Some lovely data
168
+ ```ruby
169
+ article = Article.new
170
+ article.title = "This is a great read!"
171
+ article.save #=> Boolean: Will attempt to POST to /articles
172
+ article.errors?
173
+ article.errors #=> Array of errors
193
174
  ```
194
175
 
195
- ##### Custom paginators
196
- Since the JSON API Spec does not dictate [how to paginate](http://jsonapi.org/format/#fetching-pagination), Munson has been designed to make adding custom paginators pretty easy.
176
+ Updating a resource
197
177
 
198
178
  ```ruby
199
- class CustomPaginator
200
- # @param [Hash] Hash of options like max/default page size
201
- def initialize(opts={})
202
- end
179
+ article = Article.find(9)
180
+ article.title = "This is a great read!"
181
+ article.save #=> Boolean: Will attempt to PATCH to /articles
182
+ article.errors?
183
+ article.errors #=> Array of errors
184
+ ```
203
185
 
204
- # @param [Hash] Hash to set the 'limit' and 'offset' to be returned later by #to_params
205
- def set(params={})
206
- end
186
+ ### Accessing Side Loaded Resources
207
187
 
208
- # @return [Hash] Params to be merged into query builder.
209
- def to_params
210
- { page: {} }
211
- end
212
- end
188
+ Given the following relationship:
213
189
 
214
- ```
190
+ ```ruby
191
+ class Article < Munson::Resource
192
+ self.type = :articles
193
+ has_one :author
194
+ has_many :comments
215
195
 
216
- ### Munson::Resource
196
+ key_type :integer
197
+ attribute :title, :string
198
+ end
217
199
 
218
- A munson resource provides a DSL in the including class for doing common JSON API queries on your ruby class.
200
+ class Person < Munson::Resource
201
+ self.type = :people
202
+ has_many :articles
219
203
 
220
- It delegates a set of methods so that they dont have to be accessed through the ```munson``` class method and sets a few options based on the including class name.
204
+ attribute :first_name, String
205
+ attribute :last_name, :string
206
+ attribute :twitter, :string
207
+ attribute :created_at, :time, default: ->{ Time.now }, serialize: ->(val){ val.to_s }
208
+ attribute :post_count, :integer
209
+ end
221
210
 
222
- It also will alter the response objects coming from #fetch and #find. Instead of returning a json hash like
223
- when using the bare Munson::Agent, Munson::Resource will pass the JSON Spec attributes and the ID as a hash into your class's initializer.
211
+ class Comment < Munson::Resource
212
+ self.type = :comments
213
+ has_one :author
224
214
 
225
- ```ruby
226
- class Product
227
- include Munson::Resource
228
- register_munson_type :products
215
+ attribute :body, ->(val){ val.to_s }
216
+ attribute :score, :float
217
+ attribute :created_at, :time
218
+ attribute :is_spam, :boolean
219
+ attribute :mentions, :string, array: true
229
220
  end
230
-
231
- # Munson method is there, should you be looking for it.
232
- Product.munson #=> Munson::Agent
233
221
  ```
234
222
 
235
- **Setting the type**
223
+ **Note:** When specifying relationships in Munson, you are specifying the JSON API type name. You'll notice below that when ```.author``` is called it returns a person object. That it is because in the HTTP response, the relationship name is ```author``` but the resource type is ```people```.
224
+
225
+ ```json
226
+ {
227
+ "data": [{
228
+ "type": "articles",
229
+ "id": "1",
230
+ "attributes": {
231
+ "title": "JSON API paints my bikeshed!"
232
+ },
233
+ "relationships": {
234
+ "author": {
235
+ "links": {
236
+ "self": "http://example.com/articles/1/relationships/author",
237
+ "related": "http://example.com/articles/1/author"
238
+ },
239
+ "data": { "type": "people", "id": "9" }
240
+ }
241
+ }
242
+ }]
243
+ }
244
+ ```
236
245
 
237
- This will cause Munson to return a hash instead of a class instance (Product).
246
+ Munson initializes objects for side loaded resources. Only 1 HTTP call is made.
238
247
 
239
248
  ```ruby
240
- class Product
241
- include Munson::Resource
242
- munson.type = :products
243
- end
249
+ article = Article.include(:author, :comments).find(9)
250
+ article.author #=> Person object
251
+ article.comments #=> Munson::Collection<Comment>
252
+
253
+ article.author.first_name #=> Chauncy
244
254
  ```
245
255
 
246
- There are two ways to set the JSON API type when using a Munson::Resource
247
256
 
248
- **Registering the type**
249
257
 
250
- This will cause munson to return your model's datatype. Munson will register this in its type map dictionary and use the class to initialize a model
258
+ ## Configuration
259
+
260
+ Munson is designed to support multiple connections or API endpoints. A connection is a wrapper around Faraday::Connection that includes a few pieces of middleware for parsing and encoding requests and responses to JSON API Spec.
261
+
262
+ Setting the default connection:
251
263
 
252
264
  ```ruby
253
- class Product
254
- include Munson::Resource
255
- register_munson_type :products
265
+ Munson.configure(url: 'http://api.example.com') do |c|
266
+ c.use MyCustomMiddleware
267
+ c.use AllTheMiddlewares
256
268
  end
257
269
  ```
258
270
 
259
- #### Filtering
271
+ Each Munson::Resource has its own Munson::Client. The client *copies* the default connection so its easy to set general configuration options, and overwrite them on a resource by resource basis.
260
272
 
261
273
  ```ruby
262
- query = Product.filter(min_price: 30, max_price: 65)
263
- # its chainable
264
- query.filter(category: 'Hats').filter(size: ['small', 'medium'])
274
+ Munson.configure(url: 'http://api.example.com', response_key_format: :dasherize)
265
275
 
266
- query.to_params
267
- #=> {:filter=>{:min_price=>"30", :max_price=>"65", :category=>"Hats", :size=>"small,medium"}}
276
+ class Kitten < Munson::Resource
277
+ munson.url = "http://api.differentsite.com"
278
+ end
268
279
 
269
- query.fetch #=> Munson::Collection<Product,Product>
280
+ # Overwritten URL
281
+ Kitten.munson.connection.url #=> "http://api.differentsite.com"
282
+ # Copied key format
283
+ Kitten.munson.connection.response_key_format #=> :dasherize
284
+
285
+ Munson.default_connection.url #=> "http://api.example.com"
286
+ Munson.default_connection.response_key_format #=> :dasherize
270
287
  ```
271
288
 
272
- #### Sorting
289
+ ### Configuration Options
273
290
 
274
291
  ```ruby
275
- query = Product.sort(created_at: :desc)
276
- # its chainable
277
- query.sort(:price) # defaults to ASC
292
+ Munson.configure(url: 'http://api.example.com', response_key_format: :dasherize) do |conn|
293
+ conn.use SomeCoolFaradayMiddleware
294
+ end
295
+ ```
278
296
 
279
- query.to_params
280
- #=> {:sort=>"-created_at,price"}
297
+ Two special options can be passed into ```.configure```:
298
+ * ```url``` the base url for this endpoint
299
+ * ```response_key_format``` the format of the JSONAPI response keys. Valid values are: ```:dasherize```, ```:camelize```, ```nil```
281
300
 
282
- query.fetch #=> Munson::Collection<Product,Product>
283
- ```
301
+ Additinally any Faraday Connection options can be passed. [Faraday::Connection options](https://github.com/lostisland/faraday/blob/master/lib/faraday/connection.rb Faraday::Connection)
284
302
 
285
- #### Including (Side loading related resources)
286
303
 
287
- ```ruby
288
- query = Product.includes(:manufacturer)
289
- # its chainable
290
- query.includes(:vendor)
304
+ ## Advanced Usage
291
305
 
292
- query.to_params
293
- #=> {:include=>"manufacturer,vendor"}
306
+ ### Custom Query Builder
294
307
 
295
- query.fetch #=> Munson::Collection<Product,Product>
296
- ```
308
+ Since the filter param's format isn't specified in the [spec](http://jsonapi.org/format/#fetching-filtering)
309
+ this implementation uses (JSONAPI::Resource's implementation](https://github.com/cerebris/jsonapi-resources#filters)
297
310
 
298
- #### Sparse Fieldsets
311
+ To override, implement your own custom query builder inheriting from {Munson::Query}
312
+ {Munson::Client} takes a Query class to use. This method could be overwritten in your Resource
299
313
 
300
314
  ```ruby
301
- query = Product.fields(products: [:name, :price])
302
- # its chainable
303
- query.includes(:manufacturer).fields(manufacturer: [:name])
304
-
305
- query.to_params
306
- #=> {:fields=>{:products=>"name,price", :manufacturer=>"name"}, :include=>"manufacturer"}
315
+ class MyBuilder < Munson::Query
316
+ def filter_to_query_value
317
+ # ... your fancier logic
318
+ end
319
+ end
307
320
 
308
- query.fetch #=> Munson::Collection<Product,Product>
321
+ Article.munson.query_builder = MyBuilder
309
322
  ```
310
323
 
311
- #### All the things!
324
+ ### Without inheriting from Munson::Resource
325
+
326
+ If for some reason you cannot inherit from Munson::Resource, you can still get a lot of JSONAPI parsing functionality
327
+
312
328
  ```ruby
313
- query = Product.
314
- filter(min_price: 30, max_price: 65).
315
- includes(:manufacturer).
316
- sort(popularity: :desc, price: :asc).
317
- fields(product: ['name', 'price'], manufacturer: ['name', 'website']).
318
- page(number: 1, limit: 100)
329
+ class Album
330
+ # Just some attr accessors, NBD
331
+ attr_accessor :id
332
+ attr_accessor :title
319
333
 
320
- query.to_params
321
- #=> {:filter=>{:min_price=>"30", :max_price=>"65"}, :fields=>{:product=>"name,price", :manufacturer=>"name,website"}, :include=>"manufacturer", :sort=>"-popularity,price", :page=>{:limit=>10}}
334
+ # Give Album a client to use
335
+ def self.munson
336
+ return @munson if @munson
337
+ @munson = Munson::Client.new
338
+ end
322
339
 
323
- query.fetch #=> Munson::Collection<Product,Product>
324
- ```
340
+ # Set the type, note, this is not being set on self
341
+ munson.type = :albums
325
342
 
326
- #### Fetching a single resource
343
+ # Register the type w/ munson
344
+ Munson.register_type(munson.type, self)
345
+
346
+ # When you aren't inherited from Munson::Resource, Munson will pass a Munson::Document to a static method called munson_initializer for you to initialze your record as you wish
347
+ def self.munson_initializer(document)
348
+ new(document.id, document.attributes[:title])
349
+ end
350
+
351
+ def initialize(id, title)
352
+ @id = id
353
+ @title = title
354
+ end
355
+ end
356
+ ```
327
357
 
328
358
  ```ruby
329
- Product.find(1) #=> product
359
+ albums = Album.munson.include(:songs).fetch
360
+ albums.first.title #=> An album title!
330
361
  ```
331
362
 
332
- #### Paginating
363
+ ### Any ol' object (Register type, add munson_initializer)
364
+
365
+ As long as a class is registered with munson and it response to munson_initializer, Munson will be able to initialize the object with or without a client
333
366
 
334
- A paged and offset paginator are included with Munson.
367
+ Extending the example above...
335
368
 
336
- Using the ```offset``` paginator
337
369
  ```ruby
338
- class Product
339
- include Munson::Resource
340
- munson.paginator = :offset
341
- munson.paginator_options = {default: 10, max: 100}
342
- end
370
+ class Song
371
+ attr_reader :name
372
+ def self.munson_initializer(document)
373
+ new(document.attributes[:name])
374
+ end
343
375
 
344
- query = Product.includes('manufacturer').page(offset: 10, limit: 25)
345
- query.to_params
346
- # => {:include=>"manufacturer", :page=>{:limit=>10, :offset=>10}}
376
+ def initialize(name)
377
+ @name = name
378
+ end
379
+ end
347
380
 
348
- query.fetch #=> Munson::Collection<Product,Product>
381
+ Munson.register_type :songs, Song
349
382
  ```
350
383
 
351
- Using the ```paged``` paginator
352
384
  ```ruby
353
- class Product
354
- include Munson::Resource
355
- munson.paginator = :paged
356
- munson.paginator_options = {default: 10, max: 100}
357
- end
358
-
359
- query = Product.includes('manufacturer').page(page: 10, size: 25)
360
- query.to_params
361
- # => {:include=>"manufacturer", :page=>{:page=>10, :size=>10}}
362
-
363
- query.fetch #=> Some lovely data
385
+ album = Album.munson.include(:songs).find(9)
386
+ album.songs #=> Munson::Collection<Song>
364
387
  ```
365
388
 
366
389
  ## Development
@@ -369,58 +392,23 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
369
392
 
370
393
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
371
394
 
372
- ## Contributing
373
-
374
- Bug reports and pull requests are welcome on GitHub at https://github.com/coryodaniel/munson.
375
-
376
- ### Munson::Model
377
- WIP see [usage](#usage)
378
-
379
- Finding related resources could set instance methods that mix/override behavior of the class level agent...
380
395
 
381
- /articles/1
382
- Article.find(1) uses Article.munson
383
-
384
- /articles/1/author
385
- article = Article.find(1) uses Article.munson
386
- article.author uses article.munson as a new connection that sets the base uri to /articles/1
396
+ ## Contributing
387
397
 
388
- ## Usage
389
- ```ruby
390
- address = Address.new
391
- address.state = "FL"
392
- address.save
393
- address.state = "CA"
394
- address.save
395
- # Mind mutex adding method accessors on... dangerous, see her, consider storing them in an @attributes hash...
396
- user = User.find(1)
397
- address = user.addresses.build
398
- address.save #posts on the relation
399
-
400
- address = Address.new({...})
401
- address = Address.new
402
- address.assign_attributes
403
- address.update_attributes
404
- address.dirty?
405
-
406
- Address.update(1, {}) #update without loading
407
- Address.destroy(1) #Destroy without loading
408
-
409
- address = Address.find(300)
410
- address.destroy
411
-
412
- Address.find(10)
413
- Address.filter(zip_code: 90210).find(10)
414
- Address.filter(zip_code: 90210).all
415
- Address.filter(zip_code: 90210).fetch
416
- Address.includes(:user, 'user.purchases').filter(active: true).all
417
- Address.includes(:user, 'user.purchases').find(10)
418
- Address.sort(city: :asc)
419
- Address.sort(city: :desc)
420
- Address.fields(:street1, :street2, {user: :name})
421
- Address.fields(:street1, :street2).fields(user: :name)
422
- addresses = Address.fields(:street1, :street2).fields(user: :name)
423
- addresses.first.shipped_products.filter(min_total: 300.00)
424
-
425
- Custom collection/member methods?
426
- ```
398
+ Bug reports and pull requests are welcome on GitHub at https://github.com/stacksocial/munson.
399
+
400
+
401
+ ## TODOS
402
+ * [ ] Update Yard docs :D
403
+ * [ ] A few pending tests :/
404
+ * [ ] Collection#next (queries for next page, if pagination present)
405
+ * [ ] Related Documents/Resources taking advantage of underlying resource[links]
406
+ * [ ] Resource should provide relationship information to the underlying document ?
407
+ * [ ] Error object to wrap an individual error
408
+ * [ ] consider enumerable protocol on a query
409
+ * [ ] Handle null/empty responses...
410
+ * [ ] munson/rails - magic up all the things
411
+ * [ ] auto set type based on pluralization (self.type = :foos)
412
+ * [ ] http://api.rubyonrails.org/classes/ActiveModel/Dirty.html ?
413
+ * [ ] Pluggable pagination (could it be a subclassed QueryBuilder? vs. a set of methods mixed into a query instance)
414
+ * [ ] Query#find([...]) find multiple records