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.
data/lib/munson.rb CHANGED
@@ -2,25 +2,46 @@ require 'json'
2
2
  require 'cgi'
3
3
  require 'faraday'
4
4
  require 'faraday_middleware'
5
+ require 'bigdecimal'
5
6
 
6
7
  require "munson/version"
7
-
8
- require "munson/middleware/encode_json_api"
9
- require "munson/middleware/json_parser"
10
-
8
+ require 'munson/agent'
9
+ require 'munson/attribute'
10
+ require "munson/client"
11
11
  require 'munson/collection'
12
- require 'munson/paginator'
13
- require 'munson/response_mapper'
14
- require 'munson/query_builder'
15
12
  require 'munson/connection'
16
- require 'munson/agent'
13
+ require 'munson/document'
14
+ require 'munson/key_formatter'
15
+ require "munson/middleware/encode_json_api"
16
+ require "munson/middleware/json_parser"
17
17
  require 'munson/resource'
18
+ require 'munson/response_mapper'
19
+ require 'munson/query'
18
20
 
19
21
  module Munson
22
+ class Error < StandardError; end;
23
+ class UnsupportedSortDirectionError < Munson::Error; end;
24
+ class UnrecognizedKeyFormatter < Munson::Error; end;
25
+ class RelationshipNotIncludedError < Munson::Error; end;
26
+ class RelationshipNotFound < Munson::Error; end;
27
+ class ClientNotSet < Munson::Error; end;
20
28
  @registered_types = {}
21
- @registered_paginators = {}
22
29
 
23
30
  class << self
31
+ # Transforms a JSONAPI hash into a Munson::Document, Munson::Resource, or arbitrary class
32
+ # @param [Munson::Document,Hash] document to transform
33
+ # @return [Munson::Document,~Munson::Resource]
34
+ def factory(document)
35
+ document = Munson::Document.new(document) if document.is_a?(Hash)
36
+ klass = Munson.lookup_type(document.type)
37
+
38
+ if klass && klass.respond_to?(:munson_initializer)
39
+ klass.munson_initializer(document)
40
+ else
41
+ document
42
+ end
43
+ end
44
+
24
45
  # Configure the default connection.
25
46
  #
26
47
  # @param [Hash] opts {Munson::Connection} configuration options
@@ -52,14 +73,6 @@ module Munson
52
73
  @registered_types[type.to_sym] = klass
53
74
  end
54
75
 
55
- def register_paginator(name, klass)
56
- @registered_paginators[name.to_sym] = klass
57
- end
58
-
59
- def lookup_paginator(name)
60
- @registered_paginators[name.to_sym]
61
- end
62
-
63
76
  # Lookup a class by JSON Spec type name
64
77
  #
65
78
  # @param [#to_sym] type JSON Spec type
@@ -67,10 +80,5 @@ module Munson
67
80
  def lookup_type(type)
68
81
  @registered_types[type.to_sym]
69
82
  end
70
-
71
- # @private
72
- def flush_types!
73
- @registered_types = {}
74
- end
75
83
  end
76
84
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: munson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory O'Daniel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-07-11 00:00:00.000000000 Z
11
+ date: 2016-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -182,15 +182,15 @@ files:
182
182
  - bin/setup
183
183
  - lib/munson.rb
184
184
  - lib/munson/agent.rb
185
+ - lib/munson/attribute.rb
186
+ - lib/munson/client.rb
185
187
  - lib/munson/collection.rb
186
188
  - lib/munson/connection.rb
189
+ - lib/munson/document.rb
190
+ - lib/munson/key_formatter.rb
187
191
  - lib/munson/middleware/encode_json_api.rb
188
192
  - lib/munson/middleware/json_parser.rb
189
- - lib/munson/model.rb
190
- - lib/munson/paginator.rb
191
- - lib/munson/paginator/offset_paginator.rb
192
- - lib/munson/paginator/paged_paginator.rb
193
- - lib/munson/query_builder.rb
193
+ - lib/munson/query.rb
194
194
  - lib/munson/resource.rb
195
195
  - lib/munson/response_mapper.rb
196
196
  - lib/munson/version.rb
data/lib/munson/model.rb DELETED
@@ -1,15 +0,0 @@
1
- # module Munson
2
- # module Model
3
- # extend ActiveSupport::Concern
4
- #
5
- # included do
6
- # self.include Munson::Resource
7
- # end
8
- #
9
- # class_methods do
10
- # def has_many(*);end;
11
- # def has_one(*);end;
12
- # def belongs_to(*);end;
13
- # end
14
- # end
15
- # end
@@ -1,45 +0,0 @@
1
- module Munson
2
- module Paginator
3
- class OffsetPaginator
4
- def initialize(options={})
5
- @max_limit = options[:max]
6
- @default_limit = options[:default]
7
- end
8
-
9
- def set(opts={})
10
- limit(opts[:limit]) if opts[:limit]
11
- offset(opts[:offset]) if opts[:offset]
12
- end
13
-
14
- def to_params
15
- {
16
- page: {
17
- limit: @limit || @default_limit || 10,
18
- offset: @offset
19
- }.select { |_, value| !value.nil? }
20
- }
21
- end
22
-
23
- private
24
-
25
- # Set limit of resources per page
26
- #
27
- # @param [Fixnum] num number of resources per page
28
- def limit(num)
29
- if @max_limit && num > @max_limit
30
- @limit = @max_limit
31
- else
32
- @limit = num
33
- end
34
- end
35
-
36
- # Set offset
37
- #
38
- # @param [Fixnum] num pages to offset
39
- def offset(num)
40
- @offset = num
41
- end
42
- end
43
- end
44
- end
45
- Munson.register_paginator(:offset, Munson::Paginator::OffsetPaginator)
@@ -1,47 +0,0 @@
1
- module Munson
2
- module Paginator
3
- class PagedPaginator
4
- def initialize(options={})
5
- @max_size = options[:max]
6
- @default_size = options[:default]
7
- end
8
-
9
- def set(opts={})
10
- number(opts[:number]) if opts[:number]
11
- size(opts[:size]) if opts[:size]
12
- end
13
-
14
- def to_params
15
- {
16
- page: {
17
- size: @size || @default_size || 10,
18
- number: @number
19
- }.select { |_, value| !value.nil? }
20
- }
21
- end
22
-
23
- private
24
-
25
- # Set number of resources per page
26
- #
27
- # @param [Fixnum] num number of resources per page
28
- def size(num)
29
- if @max_size && num > @max_size
30
- @size = @max_size
31
- else
32
- @size = num
33
- end
34
- end
35
-
36
- # Set page number
37
- #
38
- # @param [Fixnum] num page number
39
- def number(num)
40
- @number = num
41
- end
42
-
43
- end
44
- end
45
- end
46
-
47
- Munson.register_paginator(:paged, Munson::Paginator::PagedPaginator)
@@ -1,6 +0,0 @@
1
- module Munson
2
- module Paginator
3
- autoload :OffsetPaginator, "munson/paginator/offset_paginator"
4
- autoload :PagedPaginator, "munson/paginator/paged_paginator"
5
- end
6
- end
@@ -1,226 +0,0 @@
1
- module Munson
2
- class QueryBuilder
3
- attr_reader :query
4
- attr_reader :paginator
5
- attr_reader :agent
6
- class UnsupportedSortDirectionError < StandardError; end;
7
- class PaginatorNotSet < StandardError; end;
8
- class AgentNotSet < StandardError; end;
9
-
10
- # Description of method
11
- #
12
- # @param [Class] paginator: nil instantiated paginator
13
- # @param [Class] agent: nil instantiated agent to use for fetching results
14
- # @return [Type] description of returned object
15
- def initialize(paginator: nil, agent: nil)
16
- @paginator = paginator
17
- @agent = agent
18
-
19
- @query = {
20
- include: [],
21
- fields: [],
22
- filter: [],
23
- sort: []
24
- }
25
- end
26
-
27
- # @return [String] query as a query string
28
- def to_query_string
29
- Faraday::Utils.build_nested_query(to_params)
30
- end
31
-
32
- def to_s
33
- to_query_string
34
- end
35
-
36
- def to_params
37
- str = {}
38
- str[:filter] = filter_to_query_value unless @query[:filter].empty?
39
- str[:fields] = fields_to_query_value unless @query[:fields].empty?
40
- str[:include] = includes_to_query_value unless @query[:include].empty?
41
- str[:sort] = sort_to_query_value unless @query[:sort].empty?
42
-
43
- str.merge!(paginator.to_params) if paginator
44
-
45
- str
46
- end
47
-
48
- # Fetches resources using {Munson::Agent}
49
- #
50
- # @return [Array] Array of resources
51
- def fetch
52
- if @agent
53
- response = @agent.get(params: to_params)
54
- resources = ResponseMapper.new(response).resources
55
- Collection.new(resources)
56
- else
57
- raise AgentNotSet, "Agent was not set. QueryBuilder#new(agent:)"
58
- end
59
- end
60
-
61
- def paging?
62
- !!paginator
63
- end
64
-
65
- # Paginator proxy
66
- #
67
- # @return [Class,nil] paginator if set
68
- def page(opts={})
69
- if paging?
70
- paginator.set(opts)
71
- self
72
- else
73
- raise PaginatorNotSet, "Paginator was not set. QueryBuilder#new(paginator:)"
74
- end
75
- end
76
-
77
- # Chainably include related resources.
78
- #
79
- # @example including a resource
80
- # Munson::QueryBuilder.new.includes(:user)
81
- #
82
- # @example including a related resource
83
- # Munson::QueryBuilder.new.includes("user.addresses")
84
- #
85
- # @example including multiple resources
86
- # Munson::QueryBuilder.new.includes("user.addresses", "user.images")
87
- #
88
- # @param [Array<String,Symbol>] *args relationships to include
89
- # @return [Munson::QueryBuilder] self for chaining queries
90
- #
91
- # @see http://jsonapi.org/format/#fetching-includes JSON API Including Relationships
92
- def includes(*args)
93
- @query[:include] += args
94
- self
95
- end
96
-
97
- # Chainably sort results
98
- # @note Default order is ascending
99
- #
100
- # @example sorting by a single field
101
- # Munsun::QueryBuilder.new.sort(:created_at)
102
- #
103
- # @example sorting by a multiple fields
104
- # Munsun::QueryBuilder.new.sort(:created_at, :age)
105
- #
106
- # @example specifying sort direction
107
- # Munsun::QueryBuilder.new.sort(:created_at, age: :desc)
108
- #
109
- # @example specifying sort direction
110
- # Munsun::QueryBuilder.new.sort(score: :desc, :created_at)
111
- #
112
- # @param [Hash<Symbol,Symbol>, Symbol] *args fields to sort by
113
- # @return [Munson::QueryBuilder] self for chaining queries
114
- #
115
- # @see http://jsonapi.org/format/#fetching-sorting JSON API Sorting Spec
116
- def sort(*args)
117
- validate_sort_args(args.select{|arg| arg.is_a?(Hash)})
118
- @query[:sort] += args
119
- self
120
- end
121
-
122
- # Hash resouce_name: [array of attribs]
123
- def fields(*args)
124
- @query[:fields] += args
125
- self
126
- end
127
-
128
- def filter(*args)
129
- @query[:filter] += args
130
- self
131
- end
132
-
133
- def self.includes(*args)
134
- new.includes(*args)
135
- end
136
-
137
- def self.sort(*args)
138
- new.sort(*args)
139
- end
140
-
141
- def self.fields(*args)
142
- new.fields(*args)
143
- end
144
-
145
- def self.filter(*args)
146
- new.filter(*args)
147
- end
148
-
149
- protected
150
-
151
- def sort_to_query_value
152
- @query[:sort].map{|item|
153
- if item.is_a?(Hash)
154
- item.to_a.map{|name,dir|
155
- dir.to_sym == :desc ? "-#{name}" : name.to_s
156
- }
157
- else
158
- item.to_s
159
- end
160
- }.join(',')
161
- end
162
-
163
- def fields_to_query_value
164
- @query[:fields].inject({}) do |acc, hash_arg|
165
- hash_arg.each do |k,v|
166
- acc[k] ||= []
167
- v.is_a?(Array) ?
168
- acc[k] += v :
169
- acc[k] << v
170
-
171
- acc[k].map(&:to_s).uniq!
172
- end
173
-
174
- acc
175
- end.map { |k, v| [k, v.join(',')] }.to_h
176
- end
177
-
178
- def includes_to_query_value
179
- @query[:include].map(&:to_s).sort.join(',')
180
- end
181
-
182
- # Since the filter query param's format isn't specified in the [spec](http://jsonapi.org/format/#fetching-filtering)
183
- # this implemenation uses (JSONAPI::Resource's implementation](https://github.com/cerebris/jsonapi-resources#filters)
184
- #
185
- # To override, implement your own CustomQueryBuilder inheriting from {Munson::QueryBuilder}
186
- # {Munson::Agent} takes a QueryBuilder class to use. This method could be overriden in your custom class
187
- #
188
- # @example Custom Query Builder
189
- # class MyBuilder < Munson::QueryBuilder
190
- # def filter_to_query_value
191
- # # ... your fancier logic
192
- # end
193
- # end
194
- #
195
- # class Article
196
- # def self.munson
197
- # return @munson if @munson
198
- # @munson = Munson::Agent.new(
199
- # query_builder: MyBuilder
200
- # path: 'products'
201
- # )
202
- # end
203
- # end
204
- #
205
- def filter_to_query_value
206
- @query[:filter].reduce({}) do |acc, hash_arg|
207
- hash_arg.each do |k,v|
208
- acc[k] ||= []
209
- v.is_a?(Array) ? acc[k] += v : acc[k] << v
210
- acc[k].uniq!
211
- end
212
- acc
213
- end.map { |k, v| [k, v.join(',')] }.to_h
214
- end
215
-
216
- def validate_sort_args(hashes)
217
- hashes.each do |hash|
218
- hash.each do |k,v|
219
- if !%i(desc asc).include?(v.to_sym)
220
- raise UnsupportedSortDirectionError, "Unknown direction '#{v}'. Use :asc or :desc"
221
- end
222
- end
223
- end
224
- end
225
- end
226
- end