api_recipes 0.0.2 → 0.0.3

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjgxODFjMzU4NzQwMjdkMWEyYTBlMmY1NWFjZTFkNmUwMTZhZDY5MQ==
4
+ NzgxYTlmYWEyYzMyNmYyZTY1YWIwNTgxMDhjZDdkNDZmMTgzYzRjZQ==
5
5
  data.tar.gz: !binary |-
6
- MzljOTgzNWUxNDYyOTZhYjljMGYzM2FkZWY5YzI0NjQwYTU2ZWI5OQ==
6
+ NjkwYjAyNmI5MjU4YzQ1MTI1NjNkYWRmOGQxNmFmMzBiYzk4OTNhNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZThhMzdmYTY0YWNmZDU3NDVmN2M4ZTQ1YzhkYTQ5MTA0MWU4OGY2ZGFlM2Nj
10
- Y2JmN2Y3MmIwNDM2YjY3MTc0NWEyYzc1ODVlZWYzNDk4NDI5YmI5OGIxOTRm
11
- ZmIzYmViNWI1YzU4MjA1YmZkMjE5NzFlYmJiMjQxY2EzMGM5MjU=
9
+ Y2EzMWViY2NmNzQ5MmNmNmU0MWJiNWI2Mzk3M2ZiNWU0YjhhYzlhYjFiOTlh
10
+ M2RjOTNjMDBlZjIzOTlmMDQ3MzUzZDkwMjk5ODg4NDA0NWY5NTQxYTQ2Mzk1
11
+ NDk1ZmJlYjZiMDE5OTljMmIzZWVhMzM3MGQ5NDdjNGFmMWNjZWM=
12
12
  data.tar.gz: !binary |-
13
- Mjc0Y2MyNzFkNTY4Y2FjZjJmNWIwOTNjYmI0MmNmMWNhN2E0NjY3ZDUwNzU1
14
- YjRhZmZmNjExZTZkNzg0N2Y0NzdkZjVjMzhhMGJkNzUzNGY0OWFkNDlmMDlk
15
- YTg4ZTNlMGM5Zjg3MmRhZmM1YTE4NTgwMTI5NDExOTc3NDM2MmM=
13
+ MDVlMjViMjc2NzJiMGJhODdmMzMxNDk4NWMyMDEyNGU0YTYwZWViNjBjZWE3
14
+ NjA0MTNmYmI0ODFkNGZkMDNkNTBjOTYxZjkzYmUzOTJiODUzMDdkNmNjOTQz
15
+ MjgwYTkxOTAzMzgyNmQ2MTA3MGRjZjdiNDBhZmFiZmJjYzE1M2Q=
data/api_recipes.gemspec CHANGED
@@ -20,6 +20,5 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency 'oj', '~> 2.13.0'
22
22
  spec.add_dependency 'oj_mimic_json', '~> 1.0.1'
23
- spec.add_dependency 'http', '~> 0.9.0'
24
- spec.add_dependency 'activesupport', '>= 4.0.0'
23
+ spec.add_dependency 'http', '~> 1.0.0'
25
24
  end
@@ -10,10 +10,6 @@ end
10
10
  # Let's create a simple class that uses ApiRecipes
11
11
  class MyFancyClass
12
12
  include ApiRecipes
13
-
14
- # Declare the endpoints that we're going to use
15
- # Add some custom configs
16
- endpoint :github
17
13
  end
18
14
 
19
15
 
@@ -22,6 +18,7 @@ end
22
18
 
23
19
  # Get user's usernames from Github's Apis (https://github.com)
24
20
  usernames = nil
21
+
25
22
  MyFancyClass.github.users.list do |users|
26
23
  usernames = users.collect{ |user| user['login'] }
27
24
  end
@@ -1,22 +1,23 @@
1
1
  module ApiRecipes
2
2
  class Endpoint
3
3
 
4
- attr_accessor :name, :settings, :authorization, :basic_auth
4
+ attr_accessor :name, :configs, :authorization, :basic_auth
5
5
  attr_reader :resources
6
6
 
7
- def initialize(name, config)
7
+ def initialize(name, configs)
8
8
  @name = name
9
- @config = config
10
- @settings = ApiRecipes::Settings::DEFAULT.merge config.endpoints_configs[name]
9
+ @configs = ApiRecipes::Settings::DEFAULT.merge configs
11
10
 
12
11
  # Generate some_endpoint.some_resource methods
13
12
  # e.g. github.users
14
13
  @resources = [] unless @resources
15
- @settings[:routes].each do |resource, routes|
14
+ @configs[:routes].each do |resource, routes|
16
15
  @resources << resource
17
16
  res = Resource.new resource, self, routes
18
- define_singleton_method resource do
19
- res
17
+ unless respond_to? resource
18
+ define_singleton_method resource do
19
+ res
20
+ end
20
21
  end
21
22
  end
22
23
  end
@@ -139,7 +139,7 @@ module ApiRecipes
139
139
  end
140
140
 
141
141
  def settings
142
- @endpoint.settings
142
+ @endpoint.configs
143
143
  end
144
144
 
145
145
  def start_request(route, route_attributes, *pars)
@@ -15,7 +15,7 @@ module ApiRecipes
15
15
  }
16
16
 
17
17
  DEFAULT_ROUTE_ATTRIBUTES = {
18
- method: :get
18
+ method: :get
19
19
  }
20
20
 
21
21
  AVAILABLE_PARAMS_ENCODINGS = %w(form params json body)
@@ -0,0 +1,185 @@
1
+ class Hash
2
+ # Returns a new hash with all keys converted using the block operation.
3
+ #
4
+ # hash = { name: 'Rob', age: '28' }
5
+ #
6
+ # hash.transform_keys{ |key| key.to_s.upcase }
7
+ # # => {"NAME"=>"Rob", "AGE"=>"28"}
8
+ def transform_keys
9
+ return enum_for(:transform_keys) unless block_given?
10
+ result = self.class.new
11
+ each_key do |key|
12
+ result[yield(key)] = self[key]
13
+ end
14
+ result
15
+ end
16
+
17
+ # Destructively convert all keys using the block operations.
18
+ # Same as transform_keys but modifies +self+.
19
+ def transform_keys!
20
+ return enum_for(:transform_keys!) unless block_given?
21
+ keys.each do |key|
22
+ self[yield(key)] = delete(key)
23
+ end
24
+ self
25
+ end
26
+
27
+ # Returns a new hash with all keys converted to strings.
28
+ #
29
+ # hash = { name: 'Rob', age: '28' }
30
+ #
31
+ # hash.stringify_keys
32
+ # # => {"name"=>"Rob", "age"=>"28"}
33
+ def stringify_keys
34
+ transform_keys{ |key| key.to_s }
35
+ end
36
+
37
+ # Destructively convert all keys to strings. Same as
38
+ # +stringify_keys+, but modifies +self+.
39
+ def stringify_keys!
40
+ transform_keys!{ |key| key.to_s }
41
+ end
42
+
43
+ # Returns a new hash with all keys converted to symbols, as long as
44
+ # they respond to +to_sym+.
45
+ #
46
+ # hash = { 'name' => 'Rob', 'age' => '28' }
47
+ #
48
+ # hash.symbolize_keys
49
+ # # => {:name=>"Rob", :age=>"28"}
50
+ def symbolize_keys
51
+ transform_keys{ |key| key.to_sym rescue key }
52
+ end
53
+ alias_method :to_options, :symbolize_keys
54
+
55
+ # Destructively convert all keys to symbols, as long as they respond
56
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
57
+ def symbolize_keys!
58
+ transform_keys!{ |key| key.to_sym rescue key }
59
+ end
60
+ alias_method :to_options!, :symbolize_keys!
61
+
62
+ # Validate all keys in a hash match <tt>*valid_keys</tt>, raising
63
+ # ArgumentError on a mismatch.
64
+ #
65
+ # Note that keys are treated differently than HashWithIndifferentAccess,
66
+ # meaning that string and symbol keys will not match.
67
+ #
68
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
69
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
70
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
71
+ def assert_valid_keys(*valid_keys)
72
+ valid_keys.flatten!
73
+ each_key do |k|
74
+ unless valid_keys.include?(k)
75
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
76
+ end
77
+ end
78
+ end
79
+
80
+ # Returns a new hash with all keys converted by the block operation.
81
+ # This includes the keys from the root hash and from all
82
+ # nested hashes and arrays.
83
+ #
84
+ # hash = { person: { name: 'Rob', age: '28' } }
85
+ #
86
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
87
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
88
+ def deep_transform_keys(&block)
89
+ _deep_transform_keys_in_object(self, &block)
90
+ end
91
+
92
+ # Destructively convert all keys by using the block operation.
93
+ # This includes the keys from the root hash and from all
94
+ # nested hashes and arrays.
95
+ def deep_transform_keys!(&block)
96
+ _deep_transform_keys_in_object!(self, &block)
97
+ end
98
+
99
+ # Returns a new hash with all keys converted to strings.
100
+ # This includes the keys from the root hash and from all
101
+ # nested hashes and arrays.
102
+ #
103
+ # hash = { person: { name: 'Rob', age: '28' } }
104
+ #
105
+ # hash.deep_stringify_keys
106
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
107
+ def deep_stringify_keys
108
+ deep_transform_keys{ |key| key.to_s }
109
+ end
110
+
111
+ # Destructively convert all keys to strings.
112
+ # This includes the keys from the root hash and from all
113
+ # nested hashes and arrays.
114
+ def deep_stringify_keys!
115
+ deep_transform_keys!{ |key| key.to_s }
116
+ end
117
+
118
+ # Returns a new hash with all keys converted to symbols, as long as
119
+ # they respond to +to_sym+. This includes the keys from the root hash
120
+ # and from all nested hashes and arrays.
121
+ #
122
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
123
+ #
124
+ # hash.deep_symbolize_keys
125
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
126
+ def deep_symbolize_keys
127
+ deep_transform_keys{ |key| key.to_sym rescue key }
128
+ end
129
+
130
+ # Destructively convert all keys to symbols, as long as they respond
131
+ # to +to_sym+. This includes the keys from the root hash and from all
132
+ # nested hashes and arrays.
133
+ def deep_symbolize_keys!
134
+ deep_transform_keys!{ |key| key.to_sym rescue key }
135
+ end
136
+
137
+ private
138
+ # support methods for deep transforming nested hashes and arrays
139
+ def _deep_transform_keys_in_object(object, &block)
140
+ case object
141
+ when Hash
142
+ object.each_with_object({}) do |(key, value), result|
143
+ result[yield(key)] = _deep_transform_keys_in_object(value, &block)
144
+ end
145
+ when Array
146
+ object.map {|e| _deep_transform_keys_in_object(e, &block) }
147
+ else
148
+ object
149
+ end
150
+ end
151
+
152
+ def _deep_transform_keys_in_object!(object, &block)
153
+ case object
154
+ when Hash
155
+ object.keys.each do |key|
156
+ value = object.delete(key)
157
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
158
+ end
159
+ object
160
+ when Array
161
+ object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
162
+ else
163
+ object
164
+ end
165
+ end
166
+ end
167
+
168
+ class Array
169
+ # Extracts options from a set of arguments. Removes and returns the last
170
+ # element in the array if it's a hash, otherwise returns a blank hash.
171
+ #
172
+ # def options(*args)
173
+ # args.extract_options!
174
+ # end
175
+ #
176
+ # options(1, 2) # => {}
177
+ # options(1, 2, a: :b) # => {:a=>:b}
178
+ def extract_options!
179
+ if last.is_a?(Hash)
180
+ pop
181
+ else
182
+ {}
183
+ end
184
+ end
185
+ end
@@ -1,3 +1,3 @@
1
1
  module ApiRecipes
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
data/lib/api_recipes.rb CHANGED
@@ -1,26 +1,41 @@
1
1
  require 'http'
2
2
  require 'oj'
3
3
  require 'oj_mimic_json'
4
- require 'active_support/core_ext/hash/indifferent_access'
5
- require 'active_support/core_ext/hash/keys'
6
- require 'active_support/core_ext/array/extract_options'
7
4
 
5
+ require 'api_recipes/utils'
8
6
  require 'api_recipes/exceptions'
9
7
  require 'api_recipes/configuration'
10
8
  require 'api_recipes/resource'
11
9
  require 'api_recipes/endpoint'
12
10
  require 'api_recipes/settings'
13
11
 
12
+ HTTP.inspect
13
+
14
14
  module ApiRecipes
15
15
 
16
16
  def self.included(base)
17
- base.send :include, InstanceAndClassMethods
18
- base.extend ClassMethods
19
- base.extend InstanceAndClassMethods
20
- end
21
17
 
22
- class << self
23
- attr_accessor :configuration
18
+ def base.endpoint(endpoint_name, configs, obj = nil)
19
+ overwrite = false
20
+ # If no obj has given, do not overwrite the EP (i.e. use the one created on configuration phase)
21
+ # Else ff an obj has given, overwrite the EP with a new EP with new configs.
22
+ # This EP will be accessible by this obj only (both class and instance)
23
+ unless obj
24
+ obj = self
25
+ overwrite = true
26
+ end
27
+ configs = ApiRecipes._aprcps_merge_endpoints_configs(endpoint_name, configs.deep_symbolize_keys)
28
+ endpoint_name = endpoint_name.to_sym
29
+
30
+ # Define 'endpoint_name' method for the class
31
+ ApiRecipes._aprcps_define_class_endpoint endpoint_name, configs, obj, overwrite
32
+ # Define 'endpoint_name' method for the class' instances
33
+ ApiRecipes._aprcps_define_instance_endpoint endpoint_name, obj
34
+ end
35
+
36
+ configuration.endpoints_configs.each do |endpoint_name, endpoint_configs|
37
+ base.endpoint endpoint_name, endpoint_configs, base
38
+ end
24
39
  end
25
40
 
26
41
  def self.configuration
@@ -33,58 +48,63 @@ module ApiRecipes
33
48
  def self.configure
34
49
  if block_given?
35
50
  yield(configuration)
51
+ _aprcps_define_global_endpoints
36
52
  else
37
53
  configuration
38
54
  end
39
55
  end
40
56
 
41
- module ClassMethods
42
- def endpoint(name, configs = {})
43
- configs = configs.deep_symbolize_keys
44
- name = name.to_sym
45
-
46
- ep = Endpoint.new(name, merge_endpoints_configs(name, configs))
47
- # Define 'name' method for the class
48
- define_class_endpoint ep
49
- # Define 'name' method for the class' instances
50
- define_instance_endpoint ep
57
+ def self._aprcps_define_global_endpoints
58
+ configuration.endpoints_configs.each do |endpoint_name, endpoint_configs|
59
+ unless method_defined? endpoint_name
60
+ unless _aprcps_storage[endpoint_name]
61
+ _aprcps_storage[endpoint_name] = Endpoint.new endpoint_name, endpoint_configs
62
+ end
63
+ define_singleton_method endpoint_name do
64
+ _aprcps_storage[endpoint_name]
65
+ end
66
+ end
51
67
  end
68
+ end
52
69
 
53
- private
70
+ def self._aprcps_storage
71
+ unless Thread.current[:api_recipes]
72
+ Thread.current[:api_recipes] = {}
73
+ end
74
+ Thread.current[:api_recipes]
75
+ end
54
76
 
55
- def define_class_endpoint(ep)
56
- name = ep.name
57
- unless method_defined? name
58
- Thread.current[name] = ep
59
77
 
60
- define_singleton_method name do
61
- Thread.current[name]
62
- end
78
+ def self._aprcps_define_class_endpoint(ep_name, configs, obj, overwrite)
79
+ unless obj.method_defined? ep_name
80
+ if overwrite
81
+ ep = Endpoint.new(ep_name, configs)
82
+ else
83
+ ep = _aprcps_storage[ep_name]
84
+ end
85
+ obj.define_singleton_method ep_name do
86
+ ep
63
87
  end
64
88
  end
89
+ end
65
90
 
66
- def define_instance_endpoint(ep)
67
- name = ep.name
68
- send :define_method, name do
69
- Thread.current[name].clone
91
+ def self._aprcps_define_instance_endpoint(ep_name, obj)
92
+ obj.instance_eval do
93
+ unless obj.method_defined? ep_name
94
+ define_method ep_name do
95
+ self.class.send ep_name
96
+ end
70
97
  end
71
98
  end
72
99
  end
73
100
 
74
- module InstanceAndClassMethods
75
-
76
- private
77
-
78
- def merge_endpoints_configs(endpoint, configs)
79
- if configs && !configs.is_a?(Hash)
80
- raise EndpointConfigIsNotAnHash.new(endpoint)
81
- end
82
- unless ApiRecipes.configuration.endpoints_configs[endpoint]
83
- ApiRecipes.configuration.endpoints_configs[endpoint] = {}
84
- end
85
- ApiRecipes.configuration.endpoints_configs[endpoint].merge! configs
86
- ApiRecipes.configuration
101
+ def self._aprcps_merge_endpoints_configs(endpoint_name, configs)
102
+ if configs && !configs.is_a?(Hash)
103
+ raise ApiRecipes::EndpointConfigIsNotAnHash.new(endpoint_name)
104
+ end
105
+ unless ApiRecipes.configuration.endpoints_configs[endpoint_name]
106
+ ApiRecipes.configuration.endpoints_configs[endpoint_name] = {}
87
107
  end
108
+ ApiRecipes.configuration.endpoints_configs[endpoint_name].merge configs
88
109
  end
89
110
  end
90
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_recipes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Verlato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-23 00:00:00.000000000 Z
11
+ date: 2016-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -44,28 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: 0.9.0
47
+ version: 1.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: 0.9.0
55
- - !ruby/object:Gem::Dependency
56
- name: activesupport
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: 4.0.0
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ! '>='
67
- - !ruby/object:Gem::Version
68
- version: 4.0.0
54
+ version: 1.0.0
69
55
  description:
70
56
  email:
71
57
  - averlato@gmail.com
@@ -100,6 +86,7 @@ files:
100
86
  - lib/api_recipes/exceptions.rb
101
87
  - lib/api_recipes/resource.rb
102
88
  - lib/api_recipes/settings.rb
89
+ - lib/api_recipes/utils.rb
103
90
  - lib/api_recipes/version.rb
104
91
  homepage: https://github.com/madAle/api_recipes
105
92
  licenses: