evoke_client 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Justin Knowlden, Thumble Monks
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # Evoke Client
2
+
3
+ evoke-client is a simple rest-client utility for allowing your application to converse with the [Evoke Service](http://evoke.thumblemonks.com). The source code for [Evoke can be found on GitHub](http://github.com/thumblemonks/evoke) along with what Evoke is intended for.
4
+
5
+ ### Usage
6
+
7
+ evoke = Evoke.new(:url => 'http://example.com/users/unsubscribe', :callback_at => (Time.now + 86400))
8
+ evoke.save
9
+
10
+ # What happens if save fails
11
+
12
+ ### Configuration
13
+
14
+ By default, evoke-client tries to talk to the Evoke service, generously hosted by Thumble Monks :) Because Evoke itself is open source and able to be run by you anywhere you want it to, the only real configuration parameters are for the hostname and port that you want evoke-client to talk to Evoke on. For instance, when we use Evoke in our projects, we may want to test with a local instance while doing development.
15
+
16
+ To modify host and port, just set the following:
17
+
18
+ Evoke.host = "example.com"
19
+ Evoke.port = "4567"
20
+ # Choosing 4567 because Evoke is written for Sinatra
21
+
22
+ ### Installation
23
+
24
+ gem install thumblemonks-evoke_client
25
+
26
+ #### Dependencies
27
+
28
+ These should be automatically installed when you install evoke_client
29
+
30
+ * [rest-client](http://github.com/adamwiggins/rest-client)
31
+
32
+ ## License
33
+
34
+ MIT, baby! (see file named MIT-LICENSE)
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ desc 'Default task: run all tests'
6
+ task :default => [:test]
7
+
8
+ task(:set_test_env) { ENV['APP_ENV'] ||= 'test' }
9
+
10
+ task(:environment) { }
11
+
12
+ task :test => [:set_test_env]
13
+ desc 'Run all tests'
14
+ Rake::TestTask.new do |t|
15
+ t.test_files = FileList['test/*_test.rb']
16
+ t.verbose = true
17
+ end
@@ -0,0 +1,35 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "evoke_client"
3
+ s.version = "0.2.0"
4
+ s.date = "2009-06-07"
5
+ s.summary = "Rest client interface for talking REST to the evoke service"
6
+ s.email = %w[gus@gusg.us]
7
+ s.homepage = "http://github.com/thumblemonks/evoke_client"
8
+ s.description = "Rest client interface for talking REST to the evoke service"
9
+ s.authors = %w[Justin\ Knowlden]
10
+ s.post_install_message = %q{Choosy wizards choose Thumble Monks.}
11
+
12
+ s.has_rdoc = false
13
+ s.rdoc_options = ["--main", "README.markdown"]
14
+ s.extra_rdoc_files = ["README.markdown"]
15
+
16
+ s.add_dependency("rest-client", [">= 0.9.2"])
17
+
18
+ # run git ls-files to get an updated list
19
+ s.files = %w[
20
+ MIT-LICENSE
21
+ README.markdown
22
+ Rakefile
23
+ evoke_client.gemspec
24
+ lib/evoke_client.rb
25
+ lib/evoke_client/base.rb
26
+ lib/evoke_client/stub.rb
27
+ lib/query_string.rb
28
+ shoulda_macros/rest_client.rb
29
+ ]
30
+
31
+ s.test_files = %w[
32
+ test/evoke_client_test.rb
33
+ test/test_helper.rb
34
+ ]
35
+ end
@@ -0,0 +1,33 @@
1
+ require 'query_string'
2
+ require 'evoke_client/base'
3
+ require 'evoke_client/stub'
4
+
5
+ class Evoke
6
+ class ConnectionRefused < Exception; end
7
+
8
+ # Configuration
9
+
10
+ def self.test?; @test == true; end
11
+ def self.test=(setting) @test = setting; end
12
+
13
+ def self.host; @host || 'evoke.thumblemonks.com'; end
14
+ def self.host=(host) @host = host; end
15
+
16
+ def self.port; @port; end
17
+ def self.port=(port) @port = port; end
18
+
19
+ def self.host_and_port
20
+ [host, port].compact.join(':')
21
+ end
22
+
23
+ # Logic
24
+
25
+ def self.create_or_update!(*args)
26
+ prepare(*args).save
27
+ end
28
+
29
+ def self.prepare(*args)
30
+ (test? ? EvokeClient::Stub : EvokeClient::Base).new(*args)
31
+ end
32
+
33
+ end
@@ -0,0 +1,23 @@
1
+ require 'restclient'
2
+
3
+ module EvokeClient
4
+ class Base
5
+ attr_reader :params, :headers
6
+
7
+ def initialize(params={})
8
+ @evoke = ::RestClient::Resource.new("http://#{Evoke.host_and_port}/callbacks")
9
+ @params = params
10
+ @params[:callback_at] = @params[:callback_at].utc if @params[:callback_at]
11
+ @params[:data] = @params[:data].to_query_string if @params[:data]
12
+ end
13
+
14
+ def save
15
+ @evoke[params[:guid]].get
16
+ @evoke[params[:guid]].put(@params)
17
+ rescue ::RestClient::ResourceNotFound
18
+ @evoke.post(@params)
19
+ rescue Errno::ECONNREFUSED
20
+ raise Evoke::ConnectionRefused, "Connection refused while connecting to #{Evoke.host_and_port}"
21
+ end
22
+ end # Base
23
+ end # EvokeClient
@@ -0,0 +1,7 @@
1
+ module EvokeClient
2
+ class Stub
3
+ def initialize(params={}); end
4
+
5
+ def save; end
6
+ end # Stub
7
+ end # EvokeClient
@@ -0,0 +1,16 @@
1
+ module EvokeClient
2
+ module Hash
3
+ def to_query_string
4
+ map do |key, val|
5
+ "#{key}=#{val}"
6
+ end.join('&')
7
+ end
8
+ end # Hash
9
+
10
+ module String
11
+ alias_method :to_query_string, :to_s
12
+ end # String
13
+ end # EvokeClient
14
+
15
+ Hash.instance_eval { include EvokeClient::Hash }
16
+ String.instance_eval { include EvokeClient::String }
@@ -0,0 +1,16 @@
1
+ module EvokeClient
2
+ module RestClient
3
+ module Shoulda
4
+ def expect_restful_request(method, *args)
5
+ ::RestClient::Resource.any_instance.expects(method).with(*args)
6
+ end
7
+
8
+ def expect_restful_request_failure(method, *raises)
9
+ ::RestClient::Resource.any_instance.expects(method).raises(*raises)
10
+ end
11
+
12
+ end # Shoulda
13
+ end # RestClient
14
+ end # EvokeClient
15
+
16
+ Test::Unit::TestCase.instance_eval { include EvokeClient::RestClient::Shoulda }
@@ -0,0 +1,104 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class EvokeTest < Test::Unit::TestCase
4
+ def setup
5
+ @params = {:url => 'foo', :callback_at => Time.now}
6
+ end
7
+
8
+ def teardown
9
+ Evoke.test = false
10
+ end
11
+
12
+ context "preparing an evokation" do
13
+ setup do
14
+ @data = {:foo => 'bar', 'goo' => 'car'}
15
+ @expected_data = "foo=bar&goo=car"
16
+ @evoke = Evoke.prepare(@params.merge(:data => @data))
17
+ end
18
+
19
+ before_should("convert times to UTC") { Time.any_instance.expects(:utc) }
20
+
21
+ should "convert data to a single escaped parameter string" do
22
+ assert_match /foo=bar&?/, @evoke.params[:data]
23
+ assert_match /goo=car&?/, @evoke.params[:data]
24
+ end
25
+ end
26
+
27
+ context "saving" do
28
+ context "a new callback" do
29
+ setup do
30
+ expect_restful_request_failure(:get, ::RestClient::ResourceNotFound)
31
+ expect_restful_request(:post, @params)
32
+ @evoke = Evoke.prepare(@params)
33
+ end
34
+ should("try and post params after not finding a resource") { @evoke.save }
35
+ end
36
+
37
+ context "an existing callback" do
38
+ setup do
39
+ expect_restful_request(:get)
40
+ expect_restful_request(:put, @params)
41
+ @evoke = Evoke.prepare(@params)
42
+ end
43
+ should("try and put params after finding a resource") { @evoke.save }
44
+ end
45
+ end
46
+
47
+ context "create_or_update!" do
48
+ should "initialize instance and call save" do
49
+ fake_evoke = EvokeClient::Base.new
50
+ EvokeClient::Base.expects(:new).with(@params).returns(fake_evoke)
51
+ fake_evoke.expects(:save)
52
+ Evoke.create_or_update!(@params)
53
+ end
54
+ end
55
+
56
+ context "connection refused" do
57
+ setup do
58
+ expect_restful_request_failure(:get, Errno::ECONNREFUSED)
59
+ end
60
+
61
+ should "reraise Evoke::ConnectionRefused when saving" do
62
+ assert_raise(Evoke::ConnectionRefused) { Evoke.prepare({}).save }
63
+ end
64
+
65
+ should "reraise Evoke::ConnectionRefused when storing" do
66
+ assert_raise(Evoke::ConnectionRefused) { Evoke.create_or_update!({}) }
67
+ end
68
+ end
69
+
70
+ context "host and port:" do
71
+ context "when unchanged" do
72
+ setup do
73
+ Evoke.host = nil
74
+ Evoke.port = nil
75
+ end
76
+ should("return default host") { assert_equal 'evoke.thumblemonks.com', Evoke.host }
77
+ should("return default port") { assert_nil Evoke.port }
78
+ should("return default host and port") { assert_equal 'evoke.thumblemonks.com', Evoke.host_and_port }
79
+ end
80
+
81
+ context "when changed" do
82
+ setup do
83
+ Evoke.host = 'example.com'
84
+ Evoke.port = 4567
85
+ end
86
+
87
+ should("return specified host") { assert_equal 'example.com', Evoke.host }
88
+ should("return specified port") { assert_equal 4567, Evoke.port }
89
+ should("return specified host and port") { assert_equal 'example.com:4567', Evoke.host_and_port }
90
+ end
91
+ end
92
+
93
+ context "when test mode is on" do
94
+ setup do
95
+ Evoke.test = true
96
+ @evoke = Evoke.prepare({})
97
+ end
98
+
99
+ should "expect an EvokeClient::Stub class" do
100
+ assert_kind_of EvokeClient::Stub, @evoke
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'shoulda'
3
+ require 'mocha'
4
+ require 'redgreen'
5
+
6
+ Shoulda.autoload_macros(File.join(File.dirname(__FILE__), '..'), ['.'])
7
+
8
+ require 'evoke_client'
9
+
10
+ Evoke.host = 'localhost'
11
+ Evoke.port = 4567
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evoke_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Knowlden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-07 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rest-client
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.2
24
+ version:
25
+ description: Rest client interface for talking REST to the evoke service
26
+ email:
27
+ - gus@gusg.us
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.markdown
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.markdown
37
+ - Rakefile
38
+ - evoke_client.gemspec
39
+ - lib/evoke_client.rb
40
+ - lib/evoke_client/base.rb
41
+ - lib/evoke_client/stub.rb
42
+ - lib/query_string.rb
43
+ - shoulda_macros/rest_client.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/thumblemonks/evoke_client
46
+ licenses: []
47
+
48
+ post_install_message: Choosy wizards choose Thumble Monks.
49
+ rdoc_options:
50
+ - --main
51
+ - README.markdown
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Rest client interface for talking REST to the evoke service
73
+ test_files:
74
+ - test/evoke_client_test.rb
75
+ - test/test_helper.rb