webmaster 0.1.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.
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module Webmaster
4
+ module Api
5
+
6
+ # Defines HTTP verbs
7
+ module Request
8
+
9
+ METHODS = [:get, :post, :put, :delete]
10
+ METHODS_WITH_BODIES = [:post, :put]
11
+
12
+ def get_request(path, params={}, options={})
13
+ request(:get, path, params, options)
14
+ end
15
+
16
+ def post_request(path, params={}, options={})
17
+ request(:post, path, params, options)
18
+ end
19
+
20
+ def put_request(path, params={}, options={})
21
+ request(:put, path, params, options)
22
+ end
23
+
24
+ def delete_request(path, params={}, options={})
25
+ request(:delete, path, params, options)
26
+ end
27
+
28
+ def request(method, path, params = {}, options = {})
29
+ if !METHODS.include?(method)
30
+ raise ArgumentError, "unkown http method: #{method}"
31
+ end
32
+
33
+ puts "EXECUTED: #{method} - #{path} with #{params} and #{options}" if ENV['DEBUG']
34
+
35
+ conn = connection(options)
36
+ if conn.path_prefix != '/' && path.index(conn.path_prefix) != 0 && !path.start_with?('https://', 'http://')
37
+ path = (conn.path_prefix + path).gsub(/\/(\/)*/, '/')
38
+ end
39
+
40
+ response = conn.send(method) do |request|
41
+ case method.to_sym
42
+ when *(METHODS - METHODS_WITH_BODIES)
43
+ request.body = params.delete('data') if params.has_key?('data')
44
+ request.url(path, params)
45
+ when *METHODS_WITH_BODIES
46
+ request.url(path)
47
+ request.body = self.extract_data_from_params(params) unless params.empty?
48
+ request.headers['Content-Length'] = request.body.size.to_s
49
+ end
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ def extract_data_from_params(params) # :nodoc:
56
+ return params['data'] if params.is_a?(Hash) && params.has_key?('data') && !params['data'].nil?
57
+ return params[:data] if params.is_a?(Hash) && params.has_key?(:data) && !params[:data].nil?
58
+ return params
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: utf-8
2
+
3
+ require 'webmaster/configuration'
4
+
5
+ require 'webmaster/api/authorization'
6
+ require 'webmaster/api/connection'
7
+ require 'webmaster/api/request'
8
+
9
+ module Webmaster
10
+ class Base
11
+ include Api::Authorization
12
+ include Api::Connection
13
+ include Api::Request
14
+
15
+ attr_accessor :configuration
16
+
17
+ def initialize(attributes = {})
18
+ self.configuration = Webmaster::Configuration.instance.setup(attributes.delete(:configuration) || {})
19
+ self.attributes = attributes
20
+ end
21
+
22
+ def attributes=(attributes = {})
23
+ attributes.each do |attr,value|
24
+ self.send("#{attr}=", value) if self.respond_to?("#{attr}=")
25
+ end
26
+ end
27
+
28
+ def inspect
29
+ inspection = if self.respond_to?(:attributes) && self.attributes.any?
30
+ self.attributes.collect { |attribute, value|
31
+ "#{attribute}: #{value}" if value.present?
32
+ }.compact.join(', ')
33
+ else
34
+ self.instance_variables.map{ |variable|
35
+ "#{variable}: #{instance_variable_get(variable).inspect}"
36
+ }.compact.join(', ')
37
+ end
38
+
39
+ "#<#{self.class} #{inspection}>"
40
+ end
41
+
42
+ # Configure options and process basic authorization
43
+ # def setup(options={})
44
+ # options = Webmaster.options.merge(options)
45
+ # self.current_options = options
46
+ # Configuration.keys.each do |key|
47
+ # send("#{key}=", options[key])
48
+ # end
49
+ # end
50
+
51
+ # Responds to attribute query or attribute clear
52
+ def method_missing(method, *args, &block) # :nodoc:
53
+ case method.to_s
54
+ when /^(.*)\?$/
55
+ return !!self.send($1.to_s)
56
+ when /^clear_(.*)$/
57
+ self.send("#{$1.to_s}=", nil)
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ # Acts as setter and getter for api requests arguments parsing.
64
+ #
65
+ # Returns Arguments instance.
66
+ #
67
+ def arguments(args=(not_set = true), options={}, &block)
68
+ if not_set
69
+ @arguments
70
+ else
71
+ @arguments = Arguments.new(self, options).parse(*args, &block)
72
+ end
73
+ end
74
+
75
+ # Scope for passing request required arguments.
76
+ #
77
+ def with(args)
78
+ case args
79
+ when Hash
80
+ set args
81
+ when /.*\/.*/i
82
+ user, repo = args.split('/')
83
+ set :user => user, :repo => repo
84
+ else
85
+ ::Kernel.raise ArgumentError, 'This api does not support passed in arguments'
86
+ end
87
+ end
88
+
89
+ # Set an option to a given value
90
+ def set(option, value=(not_set=true), ignore_setter=false, &block)
91
+ raise ArgumentError, 'value not set' if block and !not_set
92
+ return self if !not_set and value.nil?
93
+
94
+ if not_set
95
+ set_options option
96
+ return self
97
+ end
98
+
99
+ if respond_to?("#{option}=") and not ignore_setter
100
+ return __send__("#{option}=", value)
101
+ end
102
+
103
+ define_accessors option, value
104
+ self
105
+ end
106
+
107
+ protected
108
+
109
+ # Set multiple options
110
+ #
111
+ def set_options(options)
112
+ unless options.respond_to?(:each)
113
+ raise ArgumentError, 'cannot iterate over value'
114
+ end
115
+ options.each { |key, value| set(key, value) }
116
+ end
117
+
118
+ def define_accessors(option, value)
119
+ setter = proc { |val| set option, val, true }
120
+ getter = proc { value }
121
+
122
+ define_singleton_method("#{option}=", setter) if setter
123
+ define_singleton_method(option, getter) if getter
124
+ end
125
+
126
+ # Dynamically define a method for setting request option
127
+ #
128
+ def define_singleton_method(method_name, content=Proc.new)
129
+ (class << self; self; end).class_eval do
130
+ undef_method(method_name) if method_defined?(method_name)
131
+ if String === content
132
+ class_eval("def #{method_name}() #{content}; end")
133
+ else
134
+ define_method(method_name, &content)
135
+ end
136
+ end
137
+ end
138
+
139
+ def objects_from_response(klass, response, prefix)
140
+ self.objects_from_array(klass, self.fetch_value(response, prefix))
141
+ end
142
+
143
+ def fetch_value(response, prefix)
144
+ response.body[prefix]
145
+ end
146
+
147
+ # @param klass [Class]
148
+ # @param array [Array]
149
+ # @return [Array<Class>]
150
+ def objects_from_array(klass, array)
151
+ array.map do |attributes|
152
+ instance = klass.new
153
+ instance.configuration = self.configuration
154
+ instance.attributes = attributes
155
+ instance
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Webmaster
4
+ class Client < Base
5
+ def hosts(reload = false)
6
+ @hosts = nil if reload
7
+ @hosts ||= self.objects_from_response(Webmaster::Host, self.request(:get, '/hosts'), :host)
8
+ end
9
+
10
+ def create_host(name)
11
+ xml = "<host><name>#{name}</name></host>"
12
+ self.request(:post, '/hosts', xml)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,111 @@
1
+ # encoding: utf-8
2
+
3
+ require 'singleton'
4
+
5
+ module Webmaster
6
+ class Configuration
7
+ include Singleton
8
+
9
+ VALID_OPTIONS_KEYS = [
10
+ :adapter,
11
+ :app_id,
12
+ :app_password,
13
+ :oauth_token,
14
+ :endpoint,
15
+ :site,
16
+ :ssl,
17
+ :user_agent,
18
+ :connection_options
19
+ ].freeze
20
+
21
+ # Other adapters are :typhoeus, :patron, :em_synchrony, :excon, :test
22
+ DEFAULT_ADAPTER = :net_http
23
+
24
+ # By default, don't set an application id
25
+ DEFAULT_APP_ID = nil
26
+
27
+ # By default, don't set an application password
28
+ DEFAULT_APP_PASSWORD = nil
29
+
30
+ # By default, don't set a user oauth access token
31
+ DEFAULT_OAUTH_TOKEN = nil
32
+
33
+ # By default, don't set a user login name
34
+ DEFAULT_LOGIN = nil
35
+
36
+ # By default, don't set a user password
37
+ DEFAULT_PASSWORD = nil
38
+
39
+ # By default, don't set a user basic authentication
40
+ DEFAULT_BASIC_AUTH = nil
41
+
42
+ # The api endpoint used to connect to Yandex.Webmaster if none is set
43
+ DEFAULT_ENDPOINT = 'https://webmaster.yandex.ru/api/v2/'.freeze
44
+
45
+ # The web endpoint used to connect to Yandex.Webmaster if none is set
46
+ DEFAULT_SITE = 'https://oauth.yandex.ru/'.freeze
47
+
48
+ # The default SSL configuration
49
+ DEFAULT_SSL = {}
50
+
51
+ # The value sent in the http header for 'User-Agent' if none is set
52
+ DEFAULT_USER_AGENT = "Webmaster Ruby Gem #{Webmaster::Version::STRING}".freeze
53
+
54
+ # By default uses the Faraday connection options if none is set
55
+ DEFAULT_CONNECTION_OPTIONS = {}
56
+
57
+ attr_accessor *VALID_OPTIONS_KEYS
58
+
59
+ def initialize
60
+ super
61
+ self.reset!
62
+ end
63
+
64
+ def keys
65
+ VALID_OPTIONS_KEYS
66
+ end
67
+
68
+ def current
69
+ VALID_OPTIONS_KEYS.inject({}) { |h, k| h[k] = send(k); h }
70
+ end
71
+
72
+ def setup(options = {})
73
+ raise ArgumentError if (options.symbolize_keys!.keys - VALID_OPTIONS_KEYS).any?
74
+ options.each { |k,v| send("#{k}=", v) }
75
+
76
+ self
77
+ end
78
+
79
+ # Reset configuration options to their defaults
80
+ #
81
+ def reset!
82
+ self.adapter = DEFAULT_ADAPTER
83
+ self.app_id = DEFAULT_APP_ID
84
+ self.app_password = DEFAULT_APP_PASSWORD
85
+ self.oauth_token = DEFAULT_OAUTH_TOKEN
86
+ self.endpoint = DEFAULT_ENDPOINT
87
+ self.site = DEFAULT_SITE
88
+ self.ssl = DEFAULT_SSL
89
+ self.user_agent = DEFAULT_USER_AGENT
90
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
91
+ self
92
+ end
93
+
94
+ # Convenience method to allow for global setting of configuration options
95
+ def configure
96
+ yield self
97
+ end
98
+
99
+ # Responds to attribute query or attribute clear
100
+ def method_missing(method, *args, &block) # :nodoc:
101
+ case method.to_s
102
+ when /^(.*)\?$/
103
+ return !!self.send($1.to_s)
104
+ when /^clear_(.*)$/
105
+ self.send("#{$1.to_s}=", nil)
106
+ else
107
+ super
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,87 @@
1
+ class Hash # :nodoc:
2
+
3
+ def except(*items) # :nodoc:
4
+ self.dup.except!(*items)
5
+ end unless method_defined?(:except)
6
+
7
+ def except!(*keys) # :nodoc:
8
+ copy = self.dup
9
+ keys.each { |key| copy.delete!(key) }
10
+ copy
11
+ end unless method_defined?(:except!)
12
+
13
+ def slice(*keys)
14
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
15
+ hash = self.class.new
16
+ keys.each { |k| hash[k] = self[k] if has_key?(k) }
17
+ hash
18
+ end unless method_defined?(:slice)
19
+
20
+ def slice!(*keys)
21
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
22
+ omit = slice(*self.keys - keys)
23
+ hash = slice(*keys)
24
+ replace(hash)
25
+ omit
26
+ end unless method_defined?(:slice!)
27
+
28
+ def symbolize_keys # :nodoc:
29
+ inject({}) do |hash, (key, value)|
30
+ hash[(key.to_sym rescue key) || key] = value
31
+ hash
32
+ end
33
+ end unless method_defined?(:symbolize_keys)
34
+
35
+ def symbolize_keys! # :nodoc:
36
+ hash = symbolize_keys
37
+ hash.each do |key, val|
38
+ hash[key] = case val
39
+ when Hash
40
+ val.symbolize_keys!
41
+ when Array
42
+ val.map do |item|
43
+ item.is_a?(Hash) ? item.symbolize_keys! : item
44
+ end
45
+ else
46
+ val
47
+ end
48
+ end
49
+ return hash
50
+ end unless method_defined?(:symbolize_keys!)
51
+
52
+ def serialize # :nodoc:
53
+ self.map { |key, val| [key, val].join("=") }.join("&")
54
+ end unless method_defined?(:serialize)
55
+
56
+ def all_keys # :nodoc:
57
+ keys = self.keys
58
+ keys.each do |key|
59
+ if self[key].is_a?(Hash)
60
+ keys << self[key].all_keys.compact.flatten
61
+ next
62
+ end
63
+ end
64
+ keys.flatten
65
+ end unless method_defined?(:all_keys)
66
+
67
+ def has_deep_key?(key)
68
+ self.all_keys.include? key
69
+ end unless method_defined?(:has_deep_key?)
70
+
71
+ def self.hash_traverse(hash, &block)
72
+ hash.each do |key, val|
73
+ block.call(key)
74
+ case val
75
+ when Hash
76
+ val.keys.each do |k|
77
+ _hash_traverse(val, &block)
78
+ end
79
+ when Array
80
+ val.each do |item|
81
+ _hash_traverse(item, &block)
82
+ end
83
+ end
84
+ end
85
+ return hash
86
+ end
87
+ end # Hash
@@ -0,0 +1,9 @@
1
+ class Object
2
+ def blank?
3
+ !self
4
+ end unless method_defined? :blank?
5
+
6
+ def present?
7
+ !blank?
8
+ end unless method_defined? :present?
9
+ end