typhoid 0.0.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 ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_STORE
4
+ .bundle
5
+ .config
6
+ coverage
7
+ InstalledFiles
8
+ lib/bundler/man
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
data/.rvmrc ADDED
@@ -0,0 +1,5 @@
1
+ rvm --create ruby-1.9.3-p125@typhoid
2
+ # Ensure that Bundler is installed, install it if it is not.
3
+ if ! command -v bundle > /dev/null; then
4
+ gem install bundler
5
+ fi
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake'
4
+
5
+ # Specify your gem's dependencies in typhoid.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,34 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ typhoid (0.0.1)
5
+ typhoeus
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.3)
11
+ ffi (1.0.11)
12
+ json_pure (1.7.3)
13
+ mime-types (1.18)
14
+ rake (0.9.2.2)
15
+ rspec (2.10.0)
16
+ rspec-core (~> 2.10.0)
17
+ rspec-expectations (~> 2.10.0)
18
+ rspec-mocks (~> 2.10.0)
19
+ rspec-core (2.10.1)
20
+ rspec-expectations (2.10.0)
21
+ diff-lcs (~> 1.1.3)
22
+ rspec-mocks (2.10.1)
23
+ typhoeus (0.4.2)
24
+ ffi (~> 1.0)
25
+ mime-types (~> 1.18)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ json_pure (>= 1.4.1)
32
+ rake
33
+ rspec
34
+ typhoid!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Doug Rohde
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # This Repository Has Moved
2
+
3
+ No new commits will be made here. Visit [sportngin/typhoid](https://github.com/sportngin/typhoid) for the latest work on this project.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ namespace :spec do
8
+ RSpec::Core::RakeTask.new(:docs) do |t|
9
+ t.rspec_opts = ["--format doc"]
10
+ end
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,76 @@
1
+ module Typhoid
2
+ module Attributes
3
+ def load_values(params = {})
4
+ @attributes = Hash[params.map { |key, value| [key.to_s, value] }]
5
+ end
6
+
7
+ def attributes
8
+ @attributes ||= {}
9
+ @attributes
10
+ end
11
+
12
+ def read_attribute(name)
13
+ attributes[name.to_s]
14
+ end
15
+ alias :[] :read_attribute
16
+
17
+ def after_build(response, exception = nil)
18
+ assign_request_error(exception) if !response.success? || !exception.nil?
19
+ end
20
+
21
+ def assign_request_error(exception = nil)
22
+ self.resource_exception = exception || StandardError.new("Could not retrieve data from remote service")
23
+ end
24
+ private :assign_request_error
25
+
26
+ def self.included(base)
27
+ base.extend(ClassMethods)
28
+ end
29
+
30
+ protected
31
+
32
+ module ClassMethods
33
+ def field(*field_names)
34
+ raise ArgumentError, "Must specify at least one field" if field_names.length == 0
35
+ @auto_init_fields ||= []
36
+ field_names.each do |field_name|
37
+ define_accessor field_name
38
+ @auto_init_fields << field_name.to_sym
39
+ end
40
+ end
41
+
42
+ def define_accessor(field_name)
43
+ define_method field_name do
44
+ attributes[field_name.to_s]
45
+ end
46
+ define_method "#{field_name}=" do |new_value|
47
+ attributes[field_name.to_s] = new_value
48
+ end
49
+ end
50
+ private :define_accessor
51
+
52
+ def auto_init_fields
53
+ @auto_init_fields || []
54
+ end
55
+
56
+ def builder
57
+ Builder
58
+ end
59
+
60
+ def parser
61
+ Parser
62
+ end
63
+
64
+ def build(klass, response)
65
+ builder.call(klass, response)
66
+ end
67
+
68
+ def load_values(object, response)
69
+ object.tap { |obj|
70
+ obj.load_values(parser.call response.body)
71
+ obj.after_build response
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ module Typhoid
2
+ class Builder
3
+ attr_reader :klass
4
+ attr_reader :response
5
+ attr_reader :body
6
+ attr_reader :parsed_body
7
+ attr_reader :exception
8
+
9
+ def self.call(klass, response)
10
+ new(klass, response).build
11
+ end
12
+
13
+ def initialize(klass, response)
14
+ @klass = klass
15
+ @response = response
16
+ @body = response.body
17
+ begin
18
+ @parsed_body = parser.call body
19
+ rescue StandardError => e
20
+ @parsed_body = {}
21
+ @exception = e
22
+ end
23
+ end
24
+
25
+ def build
26
+ array? ? build_array : build_single
27
+ end
28
+
29
+ def build_from_klass(attributes)
30
+ klass.new(attributes).tap { |item|
31
+ item.after_build(response, exception) if item.respond_to? :after_build
32
+ }
33
+ end
34
+ private :build_from_klass
35
+
36
+ def array?
37
+ parsed_body.is_a?(Array)
38
+ end
39
+ private :array?
40
+
41
+ def build_array
42
+ parsed_body.collect { |single|
43
+ build_from_klass(single)
44
+ }
45
+ end
46
+ private :build_array
47
+
48
+ def build_single
49
+ build_from_klass parsed_body
50
+ end
51
+ private :build_single
52
+
53
+ def parser
54
+ klass.parser
55
+ end
56
+ private :parser
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ module Typhoid
2
+ module Multi
3
+ def remote_resources(hydra = nil)
4
+ request_queue = RequestQueue.new(self, hydra)
5
+ yield request_queue if block_given?
6
+
7
+ request_queue.run
8
+
9
+ request_queue.requests.each do |req|
10
+ parse_queued_response req
11
+ end
12
+ end
13
+
14
+ protected
15
+
16
+ def parse_queued_response(req)
17
+ varname = "@" + req.name.to_s
18
+ req.target.instance_variable_set varname.to_sym, Typhoid::Resource.build(req.klass, req.response)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ module Typhoid
2
+ class Parser
3
+ attr_reader :json_string
4
+
5
+ def self.call(json_string)
6
+ new(json_string).parse
7
+ end
8
+
9
+ def initialize(json_string)
10
+ @json_string = json_string
11
+ end
12
+
13
+ def parse
14
+ parsed_body
15
+ end
16
+
17
+ def parsed_body
18
+ engine.call json_string
19
+ rescue
20
+ raise ReadError, json_string
21
+ end
22
+ private :parsed_body
23
+
24
+ def engine
25
+ JSON.method(:parse)
26
+ end
27
+ private :engine
28
+ end
29
+
30
+ class ReadError < StandardError
31
+ attr_reader :body
32
+ def initialize(body)
33
+ @body = body
34
+ end
35
+
36
+ def to_s
37
+ "Could not parse JSON body: #{cleaned_body}"
38
+ end
39
+
40
+ def cleaned_body
41
+ clean = body[0..10]
42
+ clean = clean + "..." if add_dots?
43
+ clean
44
+ end
45
+ private :cleaned_body
46
+
47
+ def add_dots?
48
+ body.length > 10
49
+ end
50
+ private :add_dots?
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ module Typhoid
2
+ class QueuedRequest
3
+ attr_accessor :name, :request, :target, :klass
4
+ attr_accessor :on_complete
5
+
6
+ def initialize(hydra, name, req, target)
7
+ self.name = name
8
+ self.request = Typhoeus::Request.new(req.request_uri, req.options)
9
+ self.klass = req.klass
10
+ self.target = target
11
+ hydra.queue(self.request)
12
+ end
13
+
14
+ def on_complete
15
+ self.request.on_complete do
16
+ yield self if block_given?
17
+ end
18
+ end
19
+
20
+ def status
21
+ self.request.handled_response.code
22
+ end
23
+
24
+ def response
25
+ self.request.handled_response
26
+ end
27
+
28
+ def klass
29
+ @klass
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Typhoid
2
+ class RequestBuilder
3
+ attr_accessor :klass
4
+ attr_writer :method
5
+
6
+ def initialize(klass, uri, options = {})
7
+ @uri = uri
8
+ @request_options = options
9
+ @klass = klass
10
+ end
11
+
12
+ def request_uri
13
+ @uri
14
+ end
15
+
16
+ def options
17
+ @request_options
18
+ end
19
+
20
+ def http_method
21
+ options[:method] || :get
22
+ end
23
+
24
+ def run
25
+ klass.run(self)
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,33 @@
1
+ require 'typhoeus'
2
+
3
+ module Typhoid
4
+ class RequestQueue
5
+ attr_reader :queue
6
+ attr_accessor :target
7
+
8
+ def initialize(target, hydra = nil)
9
+ @target = target
10
+ @hydra = hydra || Typhoeus::Hydra.new
11
+ end
12
+
13
+ def resource(name, req, &block)
14
+ @queue ||= []
15
+ @queue << QueuedRequest.new(@hydra, name, req, @target)
16
+ #@queue[name].on_complete &block if block != nil
17
+ end
18
+
19
+ def resource_with_target(name, req, target, &block)
20
+ @queue ||= []
21
+ @queue << QueuedRequest.new(@hydra, name, req, target)
22
+ #@queue[name].on_complete &block if block != nil
23
+ end
24
+
25
+ def requests
26
+ @queue ||= []
27
+ end
28
+
29
+ def run
30
+ @hydra.run
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,116 @@
1
+ require 'cgi'
2
+ require 'typhoid/uri'
3
+
4
+ module Typhoid
5
+ class Resource
6
+ include Typhoid::Multi
7
+ include Typhoid::Attributes
8
+
9
+ class << self
10
+ attr_accessor :site, :path
11
+ end
12
+
13
+ attr_accessor :resource_exception
14
+
15
+ def self.build_request(uri, options = {})
16
+ Typhoid::RequestBuilder.new(self, uri, options)
17
+ end
18
+
19
+ def self.run(request)
20
+ method = request.http_method
21
+ build(request.klass, (Typhoeus::Request.send method, request.request_uri, request.options))
22
+ end
23
+
24
+ def self.uri_join(*paths)
25
+ Uri.new(*paths).to_s
26
+ end
27
+
28
+ # Get this request URI based on site and path, can attach
29
+ # more paths
30
+ def self.request_uri(*more_paths)
31
+ uri_join site, path, *more_paths
32
+ end
33
+
34
+ def initialize(params = {})
35
+ load_values(params)
36
+ end
37
+
38
+ def success?
39
+ !resource_exception
40
+ end
41
+
42
+ def save!(method = nil)
43
+ save method
44
+ raise resource_exception unless success?
45
+ end
46
+
47
+ def destroy!
48
+ destroy
49
+ raise resource_exception unless success?
50
+ end
51
+
52
+ def save(method = nil)
53
+ request_and_load do
54
+ Typhoeus::Request.send save_http_method(method), save_request.request_uri, save_request.options
55
+ end
56
+ end
57
+
58
+ def destroy
59
+ request_and_load do
60
+ Typhoeus::Request.delete(delete_request.request_uri, delete_request.options)
61
+ end
62
+ end
63
+
64
+ def save_request
65
+ (new_record?) ? create_request : update_request
66
+ end
67
+
68
+ def save_http_method(method = nil)
69
+ return method if method
70
+ (new_record?) ? :post : :put
71
+ end
72
+
73
+ # Request URI is either in the object we retrieveed initially, built from
74
+ # site + path + id, or fail to the regular class#request_uri
75
+ #
76
+ # Also, check that the server we're speaking to isn't hypermedia inclined so
77
+ # look at our attributes for a URI
78
+ def request_uri
79
+ attributes["uri"] || (new_record? ? self.class.request_uri : self.class.request_uri(id))
80
+ end
81
+
82
+ def request_and_load(&block)
83
+ self.resource_exception = nil
84
+ response = yield
85
+ self.class.load_values(self, response)
86
+ success?
87
+ end
88
+
89
+ def persisted?
90
+ !new_record?
91
+ end
92
+
93
+ def new_record?
94
+ id.to_s.length < 1
95
+ end
96
+ alias new? new_record?
97
+
98
+ protected
99
+
100
+ def to_params
101
+ attributes
102
+ end
103
+
104
+ def create_request(method = :post)
105
+ Typhoid::RequestBuilder.new(self.class, request_uri, :body => to_params.to_json, :method => method, :headers => {"Content-Type" => 'application/json'})
106
+ end
107
+
108
+ def update_request(method = :put)
109
+ Typhoid::RequestBuilder.new(self.class, request_uri, :body => to_params.to_json, :method => method, :headers => {"Content-Type" => 'application/json'})
110
+ end
111
+
112
+ def delete_request(method = :delete)
113
+ Typhoid::RequestBuilder.new(self.class, request_uri, :method => method)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,37 @@
1
+ require 'uri'
2
+ module Typhoid
3
+ class Uri
4
+ private
5
+ attr_writer :base
6
+ attr_writer :paths
7
+
8
+ public
9
+ attr_reader :base
10
+ attr_reader :paths
11
+
12
+ def initialize(*paths)
13
+ self.base = URI.parse paths.shift.to_s
14
+ self.paths = sanitize(base.path) + sanitize(paths)
15
+ base.path = ""
16
+ raise "Invalid Base on #uri_join: #{base}" unless base.scheme || base.host
17
+ end
18
+
19
+ def join(*more_paths)
20
+ full_path = (paths + sanitize(more_paths)).join "/"
21
+ base.clone.merge(full_path).to_s
22
+ end
23
+
24
+ def to_s
25
+ join
26
+ end
27
+
28
+ def sanitize(*need_sanitizing)
29
+ need_sanitizing.
30
+ flatten.
31
+ compact.
32
+ map { |p| p.to_s.split("/").compact.delete_if(&:empty?) }.
33
+ flatten
34
+ end
35
+ private :sanitize
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Typhoid
2
+ VERSION = "0.0.1"
3
+ end
data/lib/typhoid.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "typhoid/version"
2
+ require 'typhoid/uri'
3
+ require 'typhoid/parser'
4
+ require 'typhoid/builder'
5
+ require "typhoid/request_queue"
6
+ require "typhoid/queued_request"
7
+ require "typhoid/multi"
8
+ require 'typhoid/attributes'
9
+ require 'typhoid/resource'
10
+ require 'typhoid/request_builder'
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'json'
9
+
10
+ Dir["spec/support/**/*.rb"].each {|f| require "./#{f}"}
11
+
12
+ RSpec.configure do |config|
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+ config.color = true
17
+ end
@@ -0,0 +1,5 @@
1
+ require 'typhoid'
2
+
3
+ class Controller
4
+ include Typhoid::Multi
5
+ end
@@ -0,0 +1,15 @@
1
+ require 'typhoid'
2
+
3
+ class Game < Typhoid::Resource
4
+ field :id
5
+ field :team_1_name
6
+ field :team_2_name
7
+ field :start_time
8
+
9
+ self.site = 'http://localhost:3000/'
10
+ self.path = 'games/'
11
+
12
+ def self.get_game
13
+ build_request("http://localhost:3000/games/1")
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ require 'typhoid'
2
+
3
+ class PlayerStat < Typhoid::Resource
4
+ field :player_name
5
+ field :goals
6
+
7
+ def self.get_stats
8
+ build_request("http://localhost:3000/stats/2")
9
+ end
10
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ module Typhoid
3
+ describe Builder do
4
+ let(:example_json) { <<-JSON
5
+ {
6
+ "metadata": {
7
+ "current_user": {
8
+ "first_name": "Jon",
9
+ "id": 1,
10
+ "last_name": "Gilmore",
11
+ "uri": "http://user-service.dev/users/1",
12
+ "user_name": "admin"
13
+ }
14
+ },
15
+ "result": {
16
+ "first_name": "Jon",
17
+ "id": 15,
18
+ "last_name": "Phenow",
19
+ "type": "orphan",
20
+ "uri": "http://user-service.dev/personas/15",
21
+ "user": null
22
+ }
23
+ }
24
+ JSON
25
+ }
26
+
27
+ let(:example_array) { <<-JSON
28
+ [{"metadata": null }, {"metadata": null }]
29
+ JSON
30
+ }
31
+ let(:klass) { Resource }
32
+ let(:response) { double body: mocked_body, success?: mocked_success }
33
+ let(:mocked_body) { example_json }
34
+ let(:mocked_success) { true }
35
+ describe "class" do
36
+ subject { Builder }
37
+ describe "call" do
38
+ subject { Builder.call klass, response }
39
+ it { should be_a Resource }
40
+ its(:attributes) { should have_key "metadata" }
41
+ its(:attributes) { should have_key "result" }
42
+ end
43
+ end
44
+
45
+ describe "instance" do
46
+ subject { Builder.new klass, response }
47
+ describe "successful" do
48
+ describe "singular" do
49
+ it "calls expected building methods" do
50
+ klass.any_instance.should_receive(:after_build).once
51
+ subject.build.should be_a Resource
52
+ end
53
+ end
54
+
55
+ describe "array" do
56
+ let(:mocked_body) { example_array }
57
+ it "calls expected building methods" do
58
+ subject.build.should be_an Array
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "unsuccessful" do
64
+ let(:mocked_success) { false }
65
+ subject { Builder.new(klass, response).build }
66
+ describe "singular" do
67
+ it { should be_a Resource }
68
+ its(:resource_exception) { should_not be_nil }
69
+ its(:attributes) { should have_key "metadata" }
70
+ end
71
+
72
+ describe "array" do
73
+ let(:mocked_body) { example_array }
74
+ subject { Builder.new(klass, response).build.first }
75
+
76
+ it { should be_a Resource }
77
+ its(:resource_exception) { should_not be_nil }
78
+ its(:attributes) { should have_key "metadata" }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'json'
3
+
4
+
5
+ describe Typhoid::Multi do
6
+ context "making multiple requests" do
7
+ before(:each) do
8
+ @fake_hydra = Typhoeus::Hydra.new
9
+ game = Typhoeus::Response.new(:code => 200, :headers => "", :body => {"team_1_name" => "Bears"}.to_json, :time => 0.03)
10
+ @fake_hydra.stub(:get, "http://localhost:3000/games/1").and_return(game)
11
+
12
+ stats = Typhoeus::Response.new(:code => 200, :headers => "",
13
+ :body => [{'player_name' => 'Bob', 'goals' => 1}, {'player_name' => 'Mike', 'goals' => 1}].to_json, :time => 0.02)
14
+ @fake_hydra.stub(:get, "http://localhost:3000/stats/2").and_return(stats)
15
+ end
16
+
17
+ it "should assign the response to instance variables" do
18
+ controller = Controller.new
19
+ controller.remote_resources(@fake_hydra) do |req|
20
+ req.resource(:game, Game.get_game)
21
+ req.resource(:stats, PlayerStat.get_stats)
22
+ end
23
+ #games returns a single object
24
+ controller.instance_variable_get("@game").class.should eql Game
25
+ controller.instance_variable_get("@game").team_1_name.should eql "Bears"
26
+
27
+ #stats returns an array
28
+ controller.instance_variable_get("@stats").class.should eql Array
29
+ controller.instance_variable_get("@stats")[0].class.should eql PlayerStat
30
+ controller.instance_variable_get("@stats")[0].player_name.should eql 'Bob'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ module Typhoid
4
+ describe Parser do
5
+ let(:example_json) { <<-JSON
6
+ {
7
+ "metadata": {
8
+ "current_user": {
9
+ "first_name": "Jon",
10
+ "id": 1,
11
+ "last_name": "Gilmore",
12
+ "uri": "http://user-service.dev/users/1",
13
+ "user_name": "admin"
14
+ }
15
+ },
16
+ "result": {
17
+ "first_name": "Jon",
18
+ "id": 15,
19
+ "last_name": "Phenow",
20
+ "type": "orphan",
21
+ "uri": "http://user-service.dev/personas/15",
22
+ "user": null
23
+ }
24
+ }
25
+ JSON
26
+ }
27
+
28
+ let(:example_array) { <<-JSON
29
+ [{"metadata": null }, {"metadata": null }]
30
+ JSON
31
+ }
32
+
33
+ describe "class" do
34
+ subject { Parser }
35
+
36
+ describe "call" do
37
+ subject { Parser.call(example_json) }
38
+
39
+ it { should be_a Hash }
40
+ it "has an expected element" do
41
+ subject["result"]["first_name"].should == "Jon"
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "instance" do
47
+ subject { Parser.new example_json }
48
+ describe "parse" do
49
+ it "looks like a hash" do
50
+ subject.parse.should be_a Hash
51
+ end
52
+
53
+ it "has an expected element" do
54
+ subject.parse["result"]["type"].should == "orphan"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoid::RequestBuilder do
4
+ context "a request builder object" do
5
+ it "should provide an http method by default" do
6
+ req = Typhoid::RequestBuilder.new(Game, 'http://localhost/')
7
+ req.http_method.should eql :get
8
+ end
9
+
10
+ it "should set http method from options" do
11
+ req = Typhoid::RequestBuilder.new(Game, 'http://localhost', :method => :post)
12
+ req.http_method.should eql :post
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,143 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoid::Resource do
4
+ it "synchronizes field with attribute" do
5
+ response_data = {"team_1_name" => 'Bears', "team_2_name" => 'Lions'}
6
+ game = Game.new(response_data)
7
+ game.team_1_name.should == 'Bears'
8
+ game.attributes["team_1_name"].should == 'Bears'
9
+ game.attributes["team_1_name"] = 'Da Bears'
10
+ game.attributes["team_1_name"].should == 'Da Bears'
11
+ game.team_1_name.should == 'Da Bears'
12
+
13
+ game.team_1_name = 'Orange'
14
+ game.team_1_name.should == 'Orange'
15
+ game.attributes["team_1_name"].should == 'Orange'
16
+ end
17
+
18
+ it "should have fields defined" do
19
+ game = Game.new
20
+ game.should respond_to(:team_1_name)
21
+ end
22
+
23
+ it "should populate defined attributes" do
24
+ response_data = {"team_1_name" => 'Bears', "team_2_name" => 'Lions'}
25
+ game = Game.new(response_data)
26
+ game.team_1_name.should eql 'Bears'
27
+ game.start_time.should be_nil
28
+ end
29
+
30
+ it "should populate attributes" do
31
+ game = Game.new({"team_1_name" => 'Bears', "team_2_name" => 'Lions'})
32
+ game.read_attribute(:team_1_name).should eql 'Bears'
33
+ game[:team_2_name].should eql 'Lions'
34
+ end
35
+
36
+ it "should return the request path" do
37
+ game = Game.new
38
+ game.request_uri.should eql "http://localhost:3000/games"
39
+ end
40
+
41
+ context "making a standalone request" do
42
+ after { hydra.clear_stubs }
43
+ let(:hydra) { Typhoeus::Hydra.hydra }
44
+ let(:game_response) { Typhoeus::Response.new(:code => 200, :headers => "", :body => {"team_1_name" => "Bears", "id" => "1"}.to_json) }
45
+ let(:failed_game_response) { Typhoeus::Response.new(:code => 404, :headers => "", :body => {}.to_json) }
46
+ it "should retrieve an object" do
47
+ hydra.stub(:get, "http://localhost:3000/games/1").and_return(game_response)
48
+
49
+ game = Game.get_game.run
50
+ game.class.should eql Game
51
+ game.team_1_name.should eql 'Bears'
52
+ end
53
+
54
+ it "raises error on save!" do
55
+ hydra.stub(:post, "http://localhost:3000/games").and_return(failed_game_response)
56
+
57
+ game = Game.new
58
+ expect { game.save! }.to raise_error
59
+ end
60
+
61
+ it "raises error on destroy!" do
62
+ hydra.stub(:delete, "http://localhost:3000/games/1").and_return(failed_game_response)
63
+
64
+ game = Game.new("id" => 1, "team_1_name" => 'Tigers')
65
+ expect { game.destroy! }.to raise_error
66
+ end
67
+
68
+ it "raises error on save!" do
69
+ hydra.stub(:post, "http://localhost:3000/games").and_return(game_response)
70
+
71
+ game = Game.new
72
+ expect { game.save! }.to_not raise_error
73
+ end
74
+
75
+ it "raises error on save!" do
76
+ hydra.stub(:delete, "http://localhost:3000/games/1").and_return(game_response)
77
+
78
+ game = Game.new("id" => 1, "team_1_name" => 'Tigers')
79
+ expect { game.destroy! }.to_not raise_error
80
+ end
81
+
82
+ it "should create an object" do
83
+ hydra.stub(:post, "http://localhost:3000/games").and_return(game_response)
84
+
85
+ game = Game.new
86
+ game.save
87
+
88
+ game.id.should == "1"
89
+ game.team_1_name.should == "Bears"
90
+ end
91
+
92
+ it "should update an object" do
93
+ update_response = Typhoeus::Response.new(:code => 200, :headers => "", :body => {"team_1_name" => "Bears", "id" => "1"}.to_json)
94
+ hydra.stub(:put, "http://localhost:3000/games/1").and_return(update_response)
95
+
96
+ game = Game.new("id" => 1, "team_1_name" => 'Tigers')
97
+ game.save
98
+
99
+ game.resource_exception.should be_nil
100
+ game.team_1_name.should == "Bears"
101
+ end
102
+
103
+ it "should delete an object" do
104
+ hydra.stub(:delete, "http://localhost:3000/games/1").and_return(game_response)
105
+
106
+ game = Game.new("id" => 1, "team_1_name" => 'Tigers')
107
+ game.destroy
108
+
109
+ game.resource_exception.should be nil
110
+
111
+ end
112
+
113
+ it "should be able to specify save http verb" do
114
+ update_response = Typhoeus::Response.new(:code => 200, :headers => "", :body => {"team_1_name" => "Bears", "id" => "1"}.to_json)
115
+ hydra.stub(:post, "http://localhost:3000/games/1").and_return(update_response)
116
+
117
+ game = Game.new("id" => 1, "team_1_name" => 'Tigers')
118
+ game.save(:post)
119
+
120
+ game.resource_exception.should be nil
121
+
122
+ end
123
+ end
124
+
125
+ context "handling bad requests" do
126
+ let(:fake_hydra) { Typhoeus::Hydra.new }
127
+ before do
128
+ bad_game = Typhoeus::Response.new(:code => 500, :headers => "", :body => "<htmlasdfasdfasdf")
129
+ fake_hydra.stub(:get, "http://localhost:3000/games/1").and_return(bad_game)
130
+ end
131
+
132
+ it "should assign an exception object on a bad request" do
133
+ controller = Controller.new
134
+ controller.remote_resources(fake_hydra) do |req|
135
+ req.resource(:game, Game.get_game)
136
+ end
137
+
138
+ bad_game = controller.instance_variable_get("@game")
139
+ bad_game.team_1_name.should be_nil
140
+ bad_game.resource_exception.class.should be_true
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoid do
4
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ module Typhoid
3
+ describe "Uri" do
4
+ subject { Uri.new *uris }
5
+ let(:uris) { ["http://localhost/", "users"] }
6
+
7
+ its(:to_s) { should == "http://localhost/users" }
8
+ it "sets base" do
9
+ subject.base.to_s.should == "http://localhost"
10
+ end
11
+
12
+ it "sets path" do
13
+ subject.paths.should == ["users"]
14
+ end
15
+
16
+ it "appends paths" do
17
+ subject.join("/","/a/","b","/c","d/").should == "http://localhost/users/a/b/c/d"
18
+ end
19
+
20
+ it "when joining it doesn't change itself" do
21
+ expect {
22
+ subject.join("/","/a/","b","/c","d/").should == "http://localhost/users/a/b/c/d"
23
+ }.
24
+ to_not change { subject.to_s }
25
+ end
26
+ end
27
+ end
data/typhoid.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/typhoid/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Doug Rohde"]
6
+ gem.email = ["doug.rohde@tstmedia.com"]
7
+ gem.description = %q{A lightweight ORM-like wrapper around Typhoeus}
8
+ gem.summary = %q{A lightweight ORM-like wrapper around Typhoeus}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "typhoid"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Typhoid::VERSION
17
+
18
+ gem.add_dependency 'typhoeus'
19
+
20
+ gem.add_development_dependency 'rspec'
21
+ gem.add_development_dependency 'json_pure', [">= 1.4.1"]
22
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typhoid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Doug Rohde
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: typhoeus
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: json_pure
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 1.4.1
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.4.1
62
+ description: A lightweight ORM-like wrapper around Typhoeus
63
+ email:
64
+ - doug.rohde@tstmedia.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rvmrc
71
+ - Gemfile
72
+ - Gemfile.lock
73
+ - LICENSE
74
+ - README.md
75
+ - Rakefile
76
+ - lib/typhoid.rb
77
+ - lib/typhoid/attributes.rb
78
+ - lib/typhoid/builder.rb
79
+ - lib/typhoid/multi.rb
80
+ - lib/typhoid/parser.rb
81
+ - lib/typhoid/queued_request.rb
82
+ - lib/typhoid/request_builder.rb
83
+ - lib/typhoid/request_queue.rb
84
+ - lib/typhoid/resource.rb
85
+ - lib/typhoid/uri.rb
86
+ - lib/typhoid/version.rb
87
+ - spec/spec_helper.rb
88
+ - spec/support/controller.rb
89
+ - spec/support/game.rb
90
+ - spec/support/player_stat.rb
91
+ - spec/typhoid/builder_spec.rb
92
+ - spec/typhoid/multi_spec.rb
93
+ - spec/typhoid/parser_spec.rb
94
+ - spec/typhoid/request_builder_spec.rb
95
+ - spec/typhoid/resource_spec.rb
96
+ - spec/typhoid/typhoid_spec.rb
97
+ - spec/typhoid/uri_spec.rb
98
+ - typhoid.gemspec
99
+ homepage: ''
100
+ licenses: []
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ segments:
112
+ - 0
113
+ hash: -3289300841199421232
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ segments:
121
+ - 0
122
+ hash: -3289300841199421232
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 1.8.24
126
+ signing_key:
127
+ specification_version: 3
128
+ summary: A lightweight ORM-like wrapper around Typhoeus
129
+ test_files:
130
+ - spec/spec_helper.rb
131
+ - spec/support/controller.rb
132
+ - spec/support/game.rb
133
+ - spec/support/player_stat.rb
134
+ - spec/typhoid/builder_spec.rb
135
+ - spec/typhoid/multi_spec.rb
136
+ - spec/typhoid/parser_spec.rb
137
+ - spec/typhoid/request_builder_spec.rb
138
+ - spec/typhoid/resource_spec.rb
139
+ - spec/typhoid/typhoid_spec.rb
140
+ - spec/typhoid/uri_spec.rb