smg 0.2.1 → 0.2.2
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/README.rdoc +1 -1
- data/lib/smg/http.rb +23 -24
- data/lib/smg/http/exceptions.rb +5 -9
- data/lib/smg/http/hooks.rb +43 -0
- data/lib/smg/http/request.rb +23 -2
- data/lib/smg/mapping.rb +1 -3
- data/lib/smg/mapping/element.rb +1 -5
- data/lib/smg/mapping/typecasts.rb +1 -1
- data/lib/smg/model.rb +4 -4
- data/lib/smg/version.rb +1 -1
- metadata +32 -37
- data/examples/crazy.rb +0 -37
- data/examples/discogs/label.rb +0 -62
- data/examples/discogs/search.rb +0 -60
- data/examples/helper.rb +0 -10
- data/examples/plant.rb +0 -88
- data/examples/twitter.rb +0 -38
- data/examples/weather.rb +0 -147
- data/spec/collect_spec.rb +0 -272
- data/spec/context_spec.rb +0 -189
- data/spec/extract_spec.rb +0 -219
- data/spec/filtering_spec.rb +0 -164
- data/spec/fixtures/discogs/948224.xml +0 -1
- data/spec/fixtures/discogs/Enzyme+Records.xml +0 -9
- data/spec/fixtures/discogs/Genosha+Recordings.xml +0 -13
- data/spec/fixtures/discogs/Ophidian.xml +0 -6
- data/spec/fixtures/fake/malus.xml +0 -18
- data/spec/fixtures/fake/valve.xml +0 -8
- data/spec/fixtures/twitter/pipopolam.xml +0 -46
- data/spec/fixtures/yahoo.weather.com.xml +0 -50
- data/spec/http/request_spec.rb +0 -186
- data/spec/http/shared/automatic.rb +0 -43
- data/spec/http/shared/non_automatic.rb +0 -36
- data/spec/http/shared/redirectable.rb +0 -30
- data/spec/http_spec.rb +0 -76
- data/spec/lib/helpers/http_helpers.rb +0 -27
- data/spec/lib/matchers/instance_methods.rb +0 -38
- data/spec/mapping/element_spec.rb +0 -241
- data/spec/mapping/typecasts_spec.rb +0 -52
- data/spec/resource_spec.rb +0 -30
- data/spec/root_spec.rb +0 -26
- data/spec/spec_helper.rb +0 -23
data/README.rdoc
CHANGED
data/lib/smg/http.rb
CHANGED
@@ -1,11 +1,22 @@
|
|
1
1
|
require 'smg/http/request'
|
2
2
|
require 'smg/http/exceptions'
|
3
|
+
require 'smg/http/hooks'
|
3
4
|
|
4
5
|
module SMG #:nodoc:
|
5
|
-
module HTTP
|
6
|
+
module HTTP #:nodoc:
|
7
|
+
|
8
|
+
VERBS = Hash[ Request::VERBS.map { |v| v.to_s.gsub(/^.*::/,'').downcase.to_sym }.zip(Request::VERBS) ]
|
6
9
|
|
7
10
|
module Model
|
8
11
|
|
12
|
+
HTTP::VERBS.keys.each do |verb|
|
13
|
+
self.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
14
|
+
def #{verb}(path, options = {})
|
15
|
+
http(:#{verb}, path, options)
|
16
|
+
end
|
17
|
+
EOS
|
18
|
+
end
|
19
|
+
|
9
20
|
def site(value)
|
10
21
|
@site = value
|
11
22
|
end
|
@@ -14,37 +25,24 @@ module SMG #:nodoc:
|
|
14
25
|
@params = value
|
15
26
|
end
|
16
27
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def head(path, options = {}, &block)
|
22
|
-
http Net::HTTP::Head, path, options, &block
|
23
|
-
end
|
24
|
-
|
25
|
-
def delete(path, options = {}, &block)
|
26
|
-
http Net::HTTP::Delete, path, options, &block
|
27
|
-
end
|
28
|
-
|
29
|
-
def post(path, options = {}, &block)
|
30
|
-
http Net::HTTP::Post, path, options, &block
|
31
|
-
end
|
32
|
-
|
33
|
-
def put(path, options = {}, &block)
|
34
|
-
http Net::HTTP::Put, path, options, &block
|
28
|
+
def on_parse(&block)
|
29
|
+
raise ArgumentError, "No block given" unless block_given?
|
30
|
+
@on_parse = block
|
35
31
|
end
|
36
32
|
|
37
33
|
private
|
38
34
|
|
39
35
|
def http(verb, path, options = {})
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
response =
|
44
|
-
|
36
|
+
options = options.dup
|
37
|
+
request = SMG::HTTP::Request.new(HTTP::VERBS[verb], uri_for(path,options.delete(:query)), options)
|
38
|
+
run_callbacks(:before_request, request, :verb => verb)
|
39
|
+
response = request.perform
|
40
|
+
run_callbacks(:after_request, response, :verb => verb)
|
41
|
+
parse @on_parse ? @on_parse[response.body] : response.body
|
45
42
|
end
|
46
43
|
|
47
44
|
def uri_for(path, query = nil)
|
45
|
+
raise "site URI missed" unless @site
|
48
46
|
ret = Addressable::URI.parse(@site)
|
49
47
|
ret.path = path
|
50
48
|
qvalues = {}
|
@@ -58,6 +56,7 @@ module SMG #:nodoc:
|
|
58
56
|
|
59
57
|
def self.append_features(base)
|
60
58
|
base.extend Model
|
59
|
+
base.extend Hooks
|
61
60
|
end
|
62
61
|
|
63
62
|
end
|
data/lib/smg/http/exceptions.rb
CHANGED
@@ -3,6 +3,8 @@ module SMG #:nodoc:
|
|
3
3
|
|
4
4
|
class ConnectionError < StandardError
|
5
5
|
|
6
|
+
attr_reader :response
|
7
|
+
|
6
8
|
def initialize(response, message = nil)
|
7
9
|
@response = response
|
8
10
|
@message = message
|
@@ -19,16 +21,10 @@ module SMG #:nodoc:
|
|
19
21
|
class RedirectionError < ConnectionError
|
20
22
|
end
|
21
23
|
|
22
|
-
class TimeoutError <
|
23
|
-
|
24
|
-
def initialize(message)
|
25
|
-
@message = message
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s
|
29
|
-
@message
|
30
|
-
end
|
24
|
+
class TimeoutError < ::Timeout::Error
|
25
|
+
end
|
31
26
|
|
27
|
+
class SSLError < StandardError
|
32
28
|
end
|
33
29
|
|
34
30
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SMG #:nodoc:
|
2
|
+
module HTTP #:nodoc:
|
3
|
+
module Hooks
|
4
|
+
|
5
|
+
def before_request(options = {}, &block)
|
6
|
+
callback(:before_request, options, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def after_request(options = {}, &block)
|
10
|
+
callback(:after_request, options, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def run_callbacks(kind, *args)
|
16
|
+
options = Hash === args.last ? args.pop : {}
|
17
|
+
callbacks(kind).each do |callback, conditions|
|
18
|
+
next unless conditions.all? { |k,v| Array === v ? v.include?(options[k]) : options[k] == v }
|
19
|
+
callback[*args]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def callback(kind, options = {}, &block)
|
24
|
+
raise ArgumentError, "Block not given" unless block_given?
|
25
|
+
conditions = {}
|
26
|
+
if options.key?(:only)
|
27
|
+
conditions[:verb] = Array(options[:only]) & HTTP::VERBS.keys
|
28
|
+
elsif options.key?(:except)
|
29
|
+
conditions[:verb] = HTTP::VERBS.keys - Array(options[:except])
|
30
|
+
end
|
31
|
+
callbacks(kind) << [block, conditions]
|
32
|
+
end
|
33
|
+
|
34
|
+
def callbacks(kind)
|
35
|
+
@callbacks ||= {}
|
36
|
+
@callbacks[kind] ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# EOF
|
data/lib/smg/http/request.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'net/https'
|
2
3
|
|
3
4
|
gem 'addressable', '>= 2.1.1'
|
4
5
|
require 'addressable/uri'
|
@@ -23,6 +24,7 @@ module SMG #:nodoc:
|
|
23
24
|
@limit = options[:no_follow] ? 1 : options[:limit] || DEFAULT_LIMIT
|
24
25
|
@body = options[:body]
|
25
26
|
@timeout = options[:timeout] ? options[:timeout].to_i : nil
|
27
|
+
@pem = options[:pem]
|
26
28
|
end
|
27
29
|
|
28
30
|
def perform
|
@@ -31,6 +33,8 @@ module SMG #:nodoc:
|
|
31
33
|
handle_response(response)
|
32
34
|
rescue Timeout::Error => e
|
33
35
|
raise TimeoutError, e.message
|
36
|
+
rescue OpenSSL::SSL::SSLError => e
|
37
|
+
raise SSLError, e.message
|
34
38
|
end
|
35
39
|
|
36
40
|
protected
|
@@ -101,6 +105,12 @@ module SMG #:nodoc:
|
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
108
|
+
def ssl?
|
109
|
+
@uri.scheme == "https"
|
110
|
+
end
|
111
|
+
|
112
|
+
alias :use_ssl? :ssl?
|
113
|
+
|
104
114
|
def setup
|
105
115
|
@request = verb.new(@uri.request_uri, @headers)
|
106
116
|
@request.basic_auth(@uri.user, @uri.password) if @uri.user && @uri.password
|
@@ -110,8 +120,19 @@ module SMG #:nodoc:
|
|
110
120
|
|
111
121
|
def http
|
112
122
|
http = @proxy ?
|
113
|
-
Net::HTTP.new(@uri.host, @uri.
|
114
|
-
Net::HTTP.new(@uri.host, @uri.
|
123
|
+
Net::HTTP.new(@uri.host, @uri.inferred_port, @proxy.host, @proxy.inferred_port, @proxy.user, @proxy.password) :
|
124
|
+
Net::HTTP.new(@uri.host, @uri.inferred_port)
|
125
|
+
|
126
|
+
if ssl?
|
127
|
+
http.use_ssl = true
|
128
|
+
if @pem
|
129
|
+
http.cert = OpenSSL::X509::Certificate.new(@pem)
|
130
|
+
http.key = OpenSSL::PKey::RSA.new(@pem)
|
131
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
132
|
+
else
|
133
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
134
|
+
end
|
135
|
+
end
|
115
136
|
|
116
137
|
return http unless @timeout
|
117
138
|
http.open_timeout = @timeout
|
data/lib/smg/mapping.rb
CHANGED
@@ -3,7 +3,6 @@ module SMG #:nodoc:
|
|
3
3
|
|
4
4
|
attr_reader :elements, :nested, :attributes
|
5
5
|
attr_reader :root
|
6
|
-
attr_reader :parsed
|
7
6
|
|
8
7
|
def initialize
|
9
8
|
@elements = {}
|
@@ -45,8 +44,7 @@ module SMG #:nodoc:
|
|
45
44
|
|
46
45
|
def handle_path(path)
|
47
46
|
ret = normalize_path(path)
|
48
|
-
ret.unshift(
|
49
|
-
ret.flatten!
|
47
|
+
ret.unshift(*@root) if @root
|
50
48
|
ret
|
51
49
|
end
|
52
50
|
|
data/lib/smg/mapping/element.rb
CHANGED
@@ -16,11 +16,7 @@ module SMG #:nodoc:
|
|
16
16
|
@context = nil
|
17
17
|
|
18
18
|
if options.key?(:context)
|
19
|
-
|
20
|
-
Array === options[:context] &&
|
21
|
-
options[:context].all?{ |c| Symbol === c }
|
22
|
-
|
23
|
-
@context = options[:context].compact
|
19
|
+
@context = Array(options[:context]).compact
|
24
20
|
@context.uniq!
|
25
21
|
@context = nil if @context.empty?
|
26
22
|
end
|
@@ -11,7 +11,7 @@ module SMG #:nodoc:
|
|
11
11
|
|
12
12
|
def [](key,value)
|
13
13
|
return typecasts[key][value] if typecasts.key?(key)
|
14
|
-
raise ArgumentError, "Can't typecast
|
14
|
+
raise ArgumentError, "Can't typecast #{value.class} into #{key.inspect}"
|
15
15
|
end
|
16
16
|
|
17
17
|
def key?(key)
|
data/lib/smg/model.rb
CHANGED
@@ -21,20 +21,20 @@ module SMG #:nodoc:
|
|
21
21
|
thing = Class === options[:class] ? mapping.attach_nested(tag,options) : mapping.attach_element(tag,options)
|
22
22
|
|
23
23
|
if (instance_methods & [thing.accessor, thing.accessor.to_s]).empty?
|
24
|
-
class_eval
|
24
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
25
25
|
def #{thing.accessor}(value)
|
26
26
|
@#{thing.name} ||= []
|
27
27
|
@#{thing.name} << value
|
28
28
|
end
|
29
|
-
|
29
|
+
EOS
|
30
30
|
end
|
31
31
|
|
32
32
|
if (instance_methods & [thing.name, thing.name.to_s]).empty?
|
33
|
-
class_eval
|
33
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
34
34
|
def #{thing.name}
|
35
35
|
@#{thing.name} ||= []
|
36
36
|
end
|
37
|
-
|
37
|
+
EOS
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|
data/lib/smg/version.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- SSDany
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-07-16 00:00:00 +04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: nokogiri
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 9
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 3
|
@@ -34,16 +37,34 @@ dependencies:
|
|
34
37
|
name: addressable
|
35
38
|
prerelease: false
|
36
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
37
41
|
requirements:
|
38
42
|
- - ">="
|
39
43
|
- !ruby/object:Gem::Version
|
44
|
+
hash: 15
|
40
45
|
segments:
|
41
46
|
- 2
|
42
47
|
- 1
|
43
|
-
-
|
44
|
-
version: 2.1.
|
48
|
+
- 2
|
49
|
+
version: 2.1.2
|
45
50
|
type: :runtime
|
46
51
|
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: rspec
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 31
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 2
|
64
|
+
- 0
|
65
|
+
version: 1.2.0
|
66
|
+
type: :development
|
67
|
+
version_requirements: *id003
|
47
68
|
description: |
|
48
69
|
XML to Object mapping library with simple declarative syntax.
|
49
70
|
Supports 'contextual' parsing and conditions.
|
@@ -60,6 +81,7 @@ files:
|
|
60
81
|
- README.rdoc
|
61
82
|
- lib/smg/document.rb
|
62
83
|
- lib/smg/http/exceptions.rb
|
84
|
+
- lib/smg/http/hooks.rb
|
63
85
|
- lib/smg/http/request.rb
|
64
86
|
- lib/smg/http.rb
|
65
87
|
- lib/smg/mapping/element.rb
|
@@ -69,37 +91,6 @@ files:
|
|
69
91
|
- lib/smg/resource.rb
|
70
92
|
- lib/smg/version.rb
|
71
93
|
- lib/smg.rb
|
72
|
-
- examples/crazy.rb
|
73
|
-
- examples/discogs/label.rb
|
74
|
-
- examples/discogs/search.rb
|
75
|
-
- examples/helper.rb
|
76
|
-
- examples/plant.rb
|
77
|
-
- examples/twitter.rb
|
78
|
-
- examples/weather.rb
|
79
|
-
- spec/collect_spec.rb
|
80
|
-
- spec/context_spec.rb
|
81
|
-
- spec/extract_spec.rb
|
82
|
-
- spec/filtering_spec.rb
|
83
|
-
- spec/fixtures/discogs/948224.xml
|
84
|
-
- spec/fixtures/discogs/Enzyme+Records.xml
|
85
|
-
- spec/fixtures/discogs/Genosha+Recordings.xml
|
86
|
-
- spec/fixtures/discogs/Ophidian.xml
|
87
|
-
- spec/fixtures/fake/malus.xml
|
88
|
-
- spec/fixtures/fake/valve.xml
|
89
|
-
- spec/fixtures/twitter/pipopolam.xml
|
90
|
-
- spec/fixtures/yahoo.weather.com.xml
|
91
|
-
- spec/http/request_spec.rb
|
92
|
-
- spec/http/shared/automatic.rb
|
93
|
-
- spec/http/shared/non_automatic.rb
|
94
|
-
- spec/http/shared/redirectable.rb
|
95
|
-
- spec/http_spec.rb
|
96
|
-
- spec/lib/helpers/http_helpers.rb
|
97
|
-
- spec/lib/matchers/instance_methods.rb
|
98
|
-
- spec/mapping/element_spec.rb
|
99
|
-
- spec/mapping/typecasts_spec.rb
|
100
|
-
- spec/resource_spec.rb
|
101
|
-
- spec/root_spec.rb
|
102
|
-
- spec/spec_helper.rb
|
103
94
|
has_rdoc: true
|
104
95
|
homepage: http://github.com/SSDany/smg
|
105
96
|
licenses: []
|
@@ -110,23 +101,27 @@ rdoc_options: []
|
|
110
101
|
require_paths:
|
111
102
|
- lib
|
112
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
113
105
|
requirements:
|
114
106
|
- - ">="
|
115
107
|
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
116
109
|
segments:
|
117
110
|
- 0
|
118
111
|
version: "0"
|
119
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
120
114
|
requirements:
|
121
115
|
- - ">="
|
122
116
|
- !ruby/object:Gem::Version
|
117
|
+
hash: 3
|
123
118
|
segments:
|
124
119
|
- 0
|
125
120
|
version: "0"
|
126
121
|
requirements: []
|
127
122
|
|
128
123
|
rubyforge_project: smg
|
129
|
-
rubygems_version: 1.3.
|
124
|
+
rubygems_version: 1.3.7
|
130
125
|
signing_key:
|
131
126
|
specification_version: 3
|
132
127
|
summary: Simple declaratibve XML parsing library. Backed by Nokogiri
|
data/examples/crazy.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
-
|
3
|
-
class A
|
4
|
-
include SMG::Resource
|
5
|
-
extract "a" , :as => :href , :at => :href
|
6
|
-
extract "a" , :as => :content
|
7
|
-
end
|
8
|
-
|
9
|
-
class P
|
10
|
-
include SMG::Resource
|
11
|
-
extract "p" , :as => :raw
|
12
|
-
collect "p/a" , :as => :links , :class => A
|
13
|
-
end
|
14
|
-
|
15
|
-
class Requirements
|
16
|
-
include SMG::Resource
|
17
|
-
root "div"
|
18
|
-
extract "p" , :as => :raw
|
19
|
-
extract "p" , :as => :p , :class => P
|
20
|
-
collect "p/a" , :as => :links , :class => A
|
21
|
-
end
|
22
|
-
|
23
|
-
data = <<-HTML
|
24
|
-
<div><p>Requirements: <a href="http://github.com/tenderlove/nokogiri">nokogiri</a> and <a href="http://github.com/sporkmonger/addressable">addressable</a>.</p></div>
|
25
|
-
HTML
|
26
|
-
|
27
|
-
parsed = Requirements.parse(data)
|
28
|
-
|
29
|
-
puts parsed.raw #=> "Requirements: nokogiri and addressable."
|
30
|
-
puts parsed.links.map { |a| a.href } #=> ["http://github.com/tenderlove/nokogiri", "http://github.com/sporkmonger/addressable"]
|
31
|
-
puts parsed.links.map { |a| a.content } #=> ["nokogiri", "addressable"]
|
32
|
-
|
33
|
-
puts parsed.p.raw #=> "Requirements: nokogiri and addressable."
|
34
|
-
puts parsed.p.links.map { |a| a.href } #=> ["http://github.com/tenderlove/nokogiri", "http://github.com/sporkmonger/addressable"]
|
35
|
-
puts parsed.p.links.map { |a| a.content } #=> ["nokogiri", "addressable"]
|
36
|
-
|
37
|
-
# EOF
|