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.
- data/.document +5 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +85 -0
- data/LICENSE.txt +20 -0
- data/README.md +94 -0
- data/Rakefile +46 -0
- data/lib/webmaster.rb +66 -0
- data/lib/webmaster/api/authorization.rb +59 -0
- data/lib/webmaster/api/connection.rb +87 -0
- data/lib/webmaster/api/request.rb +62 -0
- data/lib/webmaster/base.rb +159 -0
- data/lib/webmaster/client.rb +15 -0
- data/lib/webmaster/configuration.rb +111 -0
- data/lib/webmaster/core_ext/hash.rb +87 -0
- data/lib/webmaster/core_ext/object.rb +9 -0
- data/lib/webmaster/core_ext/string.rb +9 -0
- data/lib/webmaster/errors.rb +21 -0
- data/lib/webmaster/host.rb +154 -0
- data/lib/webmaster/hosts/crawling.rb +24 -0
- data/lib/webmaster/hosts/verification.rb +77 -0
- data/lib/webmaster/request/oauth2.rb +26 -0
- data/lib/webmaster/response/hashify.rb +59 -0
- data/lib/webmaster/version.rb +12 -0
- data/test/helper.rb +18 -0
- data/test/test_webmaster.rb +7 -0
- data/webmaster.gemspec +196 -0
- metadata +796 -0
@@ -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
|