smg 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.rdoc +1 -1
  2. data/lib/smg/http.rb +23 -24
  3. data/lib/smg/http/exceptions.rb +5 -9
  4. data/lib/smg/http/hooks.rb +43 -0
  5. data/lib/smg/http/request.rb +23 -2
  6. data/lib/smg/mapping.rb +1 -3
  7. data/lib/smg/mapping/element.rb +1 -5
  8. data/lib/smg/mapping/typecasts.rb +1 -1
  9. data/lib/smg/model.rb +4 -4
  10. data/lib/smg/version.rb +1 -1
  11. metadata +32 -37
  12. data/examples/crazy.rb +0 -37
  13. data/examples/discogs/label.rb +0 -62
  14. data/examples/discogs/search.rb +0 -60
  15. data/examples/helper.rb +0 -10
  16. data/examples/plant.rb +0 -88
  17. data/examples/twitter.rb +0 -38
  18. data/examples/weather.rb +0 -147
  19. data/spec/collect_spec.rb +0 -272
  20. data/spec/context_spec.rb +0 -189
  21. data/spec/extract_spec.rb +0 -219
  22. data/spec/filtering_spec.rb +0 -164
  23. data/spec/fixtures/discogs/948224.xml +0 -1
  24. data/spec/fixtures/discogs/Enzyme+Records.xml +0 -9
  25. data/spec/fixtures/discogs/Genosha+Recordings.xml +0 -13
  26. data/spec/fixtures/discogs/Ophidian.xml +0 -6
  27. data/spec/fixtures/fake/malus.xml +0 -18
  28. data/spec/fixtures/fake/valve.xml +0 -8
  29. data/spec/fixtures/twitter/pipopolam.xml +0 -46
  30. data/spec/fixtures/yahoo.weather.com.xml +0 -50
  31. data/spec/http/request_spec.rb +0 -186
  32. data/spec/http/shared/automatic.rb +0 -43
  33. data/spec/http/shared/non_automatic.rb +0 -36
  34. data/spec/http/shared/redirectable.rb +0 -30
  35. data/spec/http_spec.rb +0 -76
  36. data/spec/lib/helpers/http_helpers.rb +0 -27
  37. data/spec/lib/matchers/instance_methods.rb +0 -38
  38. data/spec/mapping/element_spec.rb +0 -241
  39. data/spec/mapping/typecasts_spec.rb +0 -52
  40. data/spec/resource_spec.rb +0 -30
  41. data/spec/root_spec.rb +0 -26
  42. data/spec/spec_helper.rb +0 -23
@@ -20,7 +20,7 @@ http://github.com/SSDany/smg/tree/master/examples
20
20
  == REQUIREMENTS:
21
21
 
22
22
  * nokogiri (>=1.3)
23
- * addressable (>=2.1.1)
23
+ * addressable (>=2.1.2)
24
24
 
25
25
  == LICENSE:
26
26
 
@@ -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 get(path, options = {}, &block)
18
- http Net::HTTP::Get, path, options, &block
19
- end
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
- raise "site URI missed" unless @site
41
- opts = options.dup
42
- uri = uri_for(path, opts.delete(:query))
43
- response = SMG::HTTP::Request.new(verb, uri, opts).perform
44
- parse block_given? ? yield(response) : response.body
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
@@ -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 < ConnectionError
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
@@ -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.port, @proxy.host, @proxy.port, @proxy.user, @proxy.password) :
114
- Net::HTTP.new(@uri.host, @uri.port)
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
@@ -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(@root) if @root
49
- ret.flatten!
47
+ ret.unshift(*@root) if @root
50
48
  ret
51
49
  end
52
50
 
@@ -16,11 +16,7 @@ module SMG #:nodoc:
16
16
  @context = nil
17
17
 
18
18
  if options.key?(:context)
19
- raise ArgumentError, "+options[:context]+ should be an Array of Symbols" unless
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 to #{key.inspect}"
14
+ raise ArgumentError, "Can't typecast #{value.class} into #{key.inspect}"
15
15
  end
16
16
 
17
17
  def key?(key)
@@ -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 <<-CODE
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
- CODE
29
+ EOS
30
30
  end
31
31
 
32
32
  if (instance_methods & [thing.name, thing.name.to_s]).empty?
33
- class_eval <<-CODE
33
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
34
34
  def #{thing.name}
35
35
  @#{thing.name} ||= []
36
36
  end
37
- CODE
37
+ EOS
38
38
  end
39
39
 
40
40
  end
@@ -1,5 +1,5 @@
1
1
  module SMG
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
4
4
 
5
5
  # EOF
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
- - 1
9
- version: 0.2.1
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-06-14 00:00:00 +04:00
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
- - 1
44
- version: 2.1.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.6
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
@@ -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