munson 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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