monster_mash 0.1.0 → 0.1.1

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/.gitignore CHANGED
@@ -19,3 +19,4 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ README.markdown.html
@@ -0,0 +1,146 @@
1
+ monster_mash
2
+ ============
3
+
4
+ * Typhoeus is an ancient monster.
5
+ * A monster mash is a dance party.
6
+ * This library inspired by John Nunemaker's awesomely useful HTTParty.
7
+ * By law, all Ruby libraries have to have dumbass names.
8
+
9
+ This library wraps `Typhoeus` and `Typhoeus::Hydra` and exposes an easy-to-use DSL for quickly building libraries to interact with HTTP resources. Every method you write will automatically export serial (blocking) and parallel (non-blocking) methods, so you can easily parallelize your HTTP code when possible.
10
+
11
+ Writing a method
12
+ ----------------
13
+
14
+ monster_mash has a Sinatra-like syntax, and lets you build client API methods using the
15
+ 4 HTTP verbs:
16
+
17
+ * `get(method_name, &definition_block)`
18
+ * `post(method_name, &definition_block)`
19
+ * `put(method_name, &definition_block)`
20
+ * `delete(method_name, &definition_block)`
21
+
22
+ Within each `definition_block`, you can set various Typhoeus options.
23
+
24
+ * `uri` **(required)** - the URI to hit
25
+ * `handler` **(required)** - a block to handle an HTTP response
26
+ * `params` - hash of URI params
27
+ * `body` - post body
28
+ * `headers` - hash of HTTP headers to send
29
+ * `timeout` - how long to timeout
30
+ * `cache_timeout` - how long to keep HTTP calls cached
31
+ * `user_agent` - a User-Agent string to send
32
+ * `max_redirects` - max number of redirects to follow
33
+ * `disable_ssl_peer_verification` - whether to disable SSL verification
34
+
35
+ Example: Google JSON search
36
+ ---------------------------
37
+
38
+ class GoogleJson < MonsterMash::Base
39
+ VERSION = '1.0'
40
+
41
+ # Creates a method called +search+ that takes
42
+ # a single +query+ parameter.
43
+ get(:search) do |query|
44
+ uri "http://ajax.googleapis.com/ajax/services/search/web"
45
+ params 'v' => VERSION,
46
+ 'q' => query,
47
+ 'rsz' => 'large'
48
+ handler do |response|
49
+ json = JSON.parse(response.body)
50
+
51
+ # returns results
52
+ json['responseData']['results']
53
+ end
54
+ end
55
+ end
56
+
57
+ To make serial (blocking) calls using this code, you would then call the class method:
58
+
59
+ # blocks
60
+ results = GoogleJson.search("my search query")
61
+ results.each do |result|
62
+ puts result['unescapedUrl']
63
+ # do other stuff with the response
64
+ end
65
+
66
+ The `search(query)` method returns whatever your `handler` block returns.
67
+
68
+ To make parallel (non-blocking) calls, you need an instance of Typhoeus::Hydra:
69
+
70
+ hydra = Typhoeus::Hydra.new
71
+ google = GoogleJson.new(hydra)
72
+ 10.times do
73
+ google.search("my query") do |results, error|
74
+ if error
75
+ # handle error
76
+ else
77
+ results.each do |result|
78
+ puts result['unescapedUrl']
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ # blocks until all 10 queries complete.
85
+ hydra.run
86
+
87
+ Setting defaults
88
+ ----------------
89
+
90
+ If you have Typhoeus settings you want to happen for every request, you can set them in a defaults block:
91
+
92
+ class GoogleJson < MonsterMash::Base
93
+ defaults do
94
+ user_agent "GoogleJson Ruby Library"
95
+ disable_ssl_peer_verification true
96
+ end
97
+
98
+ # ...
99
+ end
100
+
101
+ As well, if you set `params` or `headers` in the `defaults` block, any `params` or `headers` added later will be `merge`d into the hash.
102
+
103
+ class GoogleJson < MonsterMash::Base
104
+ defaults do
105
+ params 'api_key' => 'fdas'
106
+ end
107
+
108
+ # The full params hash will look like:
109
+ # :q => +query+,
110
+ # :v => '1.0',
111
+ # :api_key => 'fdas'
112
+ get(:search) do |query|
113
+ params 'q' => query,
114
+ 'v' => '1.0'
115
+ uri "..."
116
+ handler do |response|
117
+ # ...
118
+ end
119
+ end
120
+ end
121
+
122
+ Error Handling
123
+ --------------
124
+
125
+ * All serial (blocking) methods will simply raise an error if anything wrong happens. You just need to `rescue` said error.
126
+ * When interacting with Hydra requests, the block you pass to it will receive an error to it if any error was caught during the `handler`'s run. You need to check for the error in your block and handle it there.
127
+
128
+ Example Projects using monster_mash
129
+ -----------------------------------
130
+ * http://github.com/dbalatero/alchemy_api
131
+
132
+ Note on Patches/Pull Requests
133
+ -----------------------------
134
+
135
+ * Fork the project.
136
+ * Make your feature addition or bug fix.
137
+ * Add tests for it. This is important so I don't break it in a
138
+ future version unintentionally.
139
+ * Commit, do not mess with rakefile, version, or history.
140
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
141
+ * Send me a pull request. Bonus points for topic branches.
142
+
143
+ Copyright
144
+ ---------
145
+
146
+ Copyright (c) 2010 David Balatero. See LICENSE for details.
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gem.email = "dbalatero@gmail.com"
11
11
  gem.homepage = "http://github.com/dbalatero/monster_mash"
12
12
  gem.authors = ["David Balatero"]
13
- gem.add_dependency "typhoeus", ">= 0.1.23"
13
+ gem.add_dependency "typhoeus", ">= 0.1.25"
14
14
  gem.add_development_dependency "rspec", ">= 1.2.9"
15
15
  gem.add_development_dependency "typhoeus_spec_cache", ">= 0.2.1"
16
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,6 +1,5 @@
1
1
  require 'typhoeus'
2
2
 
3
- require File.dirname(__FILE__) + '/monster_mash/inheritable_attributes'
4
3
  files = Dir.glob(File.dirname(__FILE__) + '/**/*.rb')
5
4
  files.each { |f| require f }
6
5
 
@@ -4,9 +4,10 @@ module MonsterMash
4
4
  end
5
5
 
6
6
  class Base
7
- include ClassLevelInheritableAttributes
8
- inheritable_attributes :defaults
7
+ @defaults = []
8
+ @has_defaults = false
9
9
 
10
+ attr_accessor :defaults
10
11
  attr_accessor :hydra
11
12
  attr_accessor :options
12
13
 
@@ -32,8 +33,9 @@ module MonsterMash
32
33
  end
33
34
 
34
35
  def self.defaults(&block)
35
- if block_given?
36
- @defaults = block
36
+ if block_given? and !@has_defaults
37
+ @has_defaults = true
38
+ @defaults << block
37
39
  else
38
40
  @defaults
39
41
  end
@@ -73,10 +75,15 @@ module MonsterMash
73
75
  end
74
76
  end
75
77
 
78
+ def self.inherited(subclass)
79
+ subclass.instance_variable_set("@defaults", defaults.dup)
80
+ end
81
+
76
82
  private
77
83
  def self.execute(http_method, hydra, block, *args, &setup_block)
78
84
  # Create the request with defaults.
79
- request = MonsterMash::Request.new(http_method, &defaults)
85
+ request = MonsterMash::Request.new(http_method)
86
+ request.apply_defaults(defaults)
80
87
 
81
88
  # Add in user-set values.
82
89
  request.execute_dsl(*args, &setup_block)
@@ -5,6 +5,9 @@ module MonsterMash
5
5
  attr_accessor :options
6
6
  attr_accessor :errors
7
7
 
8
+ # Creates a new Request wrapper object.
9
+ #
10
+ # @param [Symbol] type of HTTP request - :get, :post, :delete, :put
8
11
  def initialize(http_method, *args, &block)
9
12
  @handler = nil
10
13
  @value = nil
@@ -13,6 +16,10 @@ module MonsterMash
13
16
  execute_dsl(*args, &block)
14
17
  end
15
18
 
19
+ def apply_defaults(default_blocks)
20
+ default_blocks.each { |block| execute_dsl(&block) }
21
+ end
22
+
16
23
  def execute_dsl(*args, &block)
17
24
  instance_exec(*args, &block) if block_given?
18
25
  end
@@ -5,27 +5,27 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{monster_mash}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David Balatero"]
12
- s.date = %q{2010-05-04}
12
+ s.date = %q{2010-05-15}
13
13
  s.description = %q{Provides a fun HTTP interface on top of Typhoeus!}
14
14
  s.email = %q{dbalatero@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.markdown",
18
+ "README.markdown.html"
18
19
  ]
19
20
  s.files = [
20
21
  ".document",
21
22
  ".gitignore",
22
23
  "LICENSE",
23
- "README.rdoc",
24
+ "README.markdown",
24
25
  "Rakefile",
25
26
  "VERSION",
26
27
  "lib/monster_mash.rb",
27
28
  "lib/monster_mash/base.rb",
28
- "lib/monster_mash/inheritable_attributes.rb",
29
29
  "lib/monster_mash/instance_exec.rb",
30
30
  "lib/monster_mash/request.rb",
31
31
  "monster_mash.gemspec",
@@ -52,16 +52,16 @@ Gem::Specification.new do |s|
52
52
  s.specification_version = 3
53
53
 
54
54
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
- s.add_runtime_dependency(%q<typhoeus>, [">= 0.1.23"])
55
+ s.add_runtime_dependency(%q<typhoeus>, [">= 0.1.25"])
56
56
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
57
57
  s.add_development_dependency(%q<typhoeus_spec_cache>, [">= 0.2.1"])
58
58
  else
59
- s.add_dependency(%q<typhoeus>, [">= 0.1.23"])
59
+ s.add_dependency(%q<typhoeus>, [">= 0.1.25"])
60
60
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
61
  s.add_dependency(%q<typhoeus_spec_cache>, [">= 0.2.1"])
62
62
  end
63
63
  else
64
- s.add_dependency(%q<typhoeus>, [">= 0.1.23"])
64
+ s.add_dependency(%q<typhoeus>, [">= 0.1.25"])
65
65
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
66
  s.add_dependency(%q<typhoeus_spec_cache>, [">= 0.2.1"])
67
67
  end
@@ -5,41 +5,46 @@ end
5
5
 
6
6
  describe MonsterMash::Base do
7
7
  describe "inheriting defaults from superclasses" do
8
- class A < MonsterMash::Base
9
- defaults do
10
- cache_timeout 9999
8
+ before(:all) do
9
+ class A < MonsterMash::Base
10
+ defaults do
11
+ cache_timeout 9999
12
+ timeout 500
13
+ end
11
14
  end
12
- end
13
15
 
14
- class B < A
15
- end
16
+ class B < A
17
+ end
16
18
 
17
- class C < A
18
- defaults do
19
- cache_timeout 100
19
+ class C < A
20
+ defaults do
21
+ cache_timeout 100
22
+ end
20
23
  end
21
24
  end
22
25
 
23
26
  it "should propagate defaults to B" do
24
27
  B.defaults.should == A.defaults
28
+ B.defaults.should have(1).thing
25
29
  end
26
30
 
27
31
  it "should allow override of defaults by C" do
28
32
  C.defaults.should_not == A.defaults
33
+ C.defaults.should have(2).things
29
34
  end
30
35
  end
31
36
 
32
37
  describe "#self.defaults" do
33
- it "should default to nil" do
34
- MockApi.defaults.should == nil
38
+ it "should default to empty array" do
39
+ MockApi.defaults.should == []
35
40
  end
36
41
 
37
42
  it "should save a defaults proc in the class" do
38
43
  defaults_block = lambda { nil }
39
44
  MockApi.defaults(&defaults_block)
40
45
 
41
- MockApi.defaults.should == defaults_block
42
- MonsterMash::Base.defaults.should == nil
46
+ MockApi.defaults.should == [defaults_block]
47
+ MonsterMash::Base.defaults.should be_empty
43
48
  end
44
49
  end
45
50
 
@@ -44,6 +44,31 @@ describe MonsterMash::Request do
44
44
  end
45
45
  end
46
46
 
47
+ describe "#apply_defaults" do
48
+ before(:all) do
49
+ class ApplyDefaultsA < MonsterMash::Base
50
+ defaults do
51
+ timeout 100
52
+ cache_timeout 9999
53
+ end
54
+ end
55
+
56
+ class ApplyDefaultsB < ApplyDefaultsA
57
+ defaults do
58
+ timeout 50
59
+ end
60
+ end
61
+ end
62
+
63
+ it "should apply the defaults in inheritance order" do
64
+ request = MonsterMash::Request.new(:get)
65
+ request.apply_defaults(ApplyDefaultsB.defaults)
66
+
67
+ request.options[:timeout].should == 50
68
+ request.options[:cache_timeout].should == 9999
69
+ end
70
+ end
71
+
47
72
  describe "#handler" do
48
73
  before(:each) do
49
74
  @request = MonsterMash::Request.new(:get)
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - David Balatero
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-04 00:00:00 -07:00
17
+ date: 2010-05-15 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -27,8 +27,8 @@ dependencies:
27
27
  segments:
28
28
  - 0
29
29
  - 1
30
- - 23
31
- version: 0.1.23
30
+ - 25
31
+ version: 0.1.25
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
@@ -67,17 +67,17 @@ extensions: []
67
67
 
68
68
  extra_rdoc_files:
69
69
  - LICENSE
70
- - README.rdoc
70
+ - README.markdown
71
+ - README.markdown.html
71
72
  files:
72
73
  - .document
73
74
  - .gitignore
74
75
  - LICENSE
75
- - README.rdoc
76
+ - README.markdown
76
77
  - Rakefile
77
78
  - VERSION
78
79
  - lib/monster_mash.rb
79
80
  - lib/monster_mash/base.rb
80
- - lib/monster_mash/inheritable_attributes.rb
81
81
  - lib/monster_mash/instance_exec.rb
82
82
  - lib/monster_mash/request.rb
83
83
  - monster_mash.gemspec
@@ -87,6 +87,7 @@ files:
87
87
  - spec/monster_mash/request_spec.rb
88
88
  - spec/spec.opts
89
89
  - spec/spec_helper.rb
90
+ - README.markdown.html
90
91
  has_rdoc: true
91
92
  homepage: http://github.com/dbalatero/monster_mash
92
93
  licenses: []
@@ -1,19 +0,0 @@
1
- = monster_mash
2
-
3
- * Typhoeus is an ancient monster.
4
- * A monster mash is a dance party.
5
- * This library inspired by John Nunemaker's awesomely useful HTTParty.
6
-
7
- == Note on Patches/Pull Requests
8
-
9
- * Fork the project.
10
- * Make your feature addition or bug fix.
11
- * Add tests for it. This is important so I don't break it in a
12
- future version unintentionally.
13
- * Commit, do not mess with rakefile, version, or history.
14
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
15
- * Send me a pull request. Bonus points for topic branches.
16
-
17
- == Copyright
18
-
19
- Copyright (c) 2010 David Balatero. See LICENSE for details.
@@ -1,25 +0,0 @@
1
- module ClassLevelInheritableAttributes
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
5
-
6
- module ClassMethods
7
- def inheritable_attributes(*args)
8
- @inheritable_attributes ||= [:inheritable_attributes]
9
- @inheritable_attributes += args
10
- args.each do |arg|
11
- class_eval %(
12
- class << self; attr_accessor :#{arg} end
13
- )
14
- end
15
- @inheritable_attributes
16
- end
17
-
18
- def inherited(subclass)
19
- @inheritable_attributes.each do |inheritable_attribute|
20
- instance_var = "@#{inheritable_attribute}"
21
- subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
22
- end
23
- end
24
- end
25
- end