purzelrakete-boomloop 0.0.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/History.txt ADDED
@@ -0,0 +1,2 @@
1
+ 0.0.1, 06.05.2008.
2
+ * First checkin
data/README.txt ADDED
@@ -0,0 +1,36 @@
1
+ This is a Ruby API with which you can access boomloop.com.
2
+
3
+ == API Documentation
4
+
5
+ You can find documentation about the underlying boomloop REST api here: http://boomloop.com/api.
6
+
7
+ == Getting started
8
+
9
+ You have to register your api client on boomloop.com before using the api. This is
10
+ a 3 step process.
11
+
12
+ 1. Start by signing up on boomloop.com and register your application. You can do that
13
+ here: http://boomloop.com/oauth/new. When you have registered your application, you will
14
+ receive a consumer key and a consumer secret.
15
+
16
+ 2. Setup the api like this: boomloop -k <your consumer key> -s <your consumer secret>
17
+ You will be given a URL – go there and authorize your application.
18
+
19
+ 3. Go back to your terminal window and press <enter>. You're registered :).
20
+
21
+ == Example API Call
22
+
23
+ Once you have authorized your client, you can make the first API call like this:
24
+
25
+ client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
26
+ connection = client.create_accesstoken
27
+ events = connection.get("/events").body
28
+
29
+ This returns the raw XML. We'll see how to get Event Objects next.
30
+
31
+ The Client takes two arguments - a config key, and an authentication name. When you authorize using
32
+ the boomloop script, a config key 'api' is created in the YAMLStore. This holds your the access
33
+ tokens so that you don't need to negotiate them every time you want to make a request.
34
+
35
+
36
+
data/bin/boomloop ADDED
@@ -0,0 +1,43 @@
1
+ #! /usr/bin/env ruby
2
+ %w(optparse ostruct).each &method(:require)
3
+ require File.dirname(__FILE__) + '/../lib/boomloop'
4
+
5
+ def error(text); puts text; exit; end
6
+
7
+ options = OpenStruct.new
8
+ parser = OptionParser.new
9
+ parser.banner = %Q{
10
+ == Usage
11
+
12
+ You have to register your api client on boomloop.com before using the api. This is
13
+ a 3 step process.
14
+
15
+ 1. Start by signing up on boomloop.com and register your application. You can do that
16
+ here: http://boomloop.com/oauth/new. When you have registered your application, you will
17
+ receive a consumer key and a consumer secret.
18
+
19
+ 2. Setup the api like this: boomloop -k <your consumer key> -s <your consumer secret>
20
+ You will be given a URL – go there and authorize your application.
21
+
22
+ 3. Go back to your terminal window and press <enter>. Now do something with the API :).
23
+
24
+ }
25
+
26
+ parser.on_tail("-h", "--help", "Show this message") { error(parser) }
27
+ parser.on("-k", "--key KEY", "Your consumer KEY") { |key| options.key = key }
28
+ parser.on("-s", "--secret SECRET", "Your consumer SECRET") { |secret| options.secret = secret }
29
+
30
+ # parse.
31
+ parser.parse!(ARGV) rescue error(parser)
32
+ error(parser) unless options.secret && options.key
33
+
34
+ # negotiate the tokens
35
+ client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
36
+ request_token = client.consume(options.key, options.secret) rescue error("Invalid. Check your credentials at http://boomloop.com/oauth/applications.")
37
+ puts "\nalmost ready! go to #{ request_token.authorize_url }\n\n press enter when you're done... <waiting>\n"
38
+
39
+ while !@access_token && gets
40
+ @access_token = client.activate rescue nil
41
+ end
42
+
43
+ puts "your keys have been activated. you're ready to use the api. \n\n"
File without changes
@@ -0,0 +1,37 @@
1
+ module Boomloop
2
+ module Authentication
3
+ class Client
4
+ attr_accessor :store, :user
5
+ attr_accessor :consumer, :request_token, :access_token
6
+
7
+ def initialize(user, store)
8
+ self.user = user
9
+ self.store = store
10
+ end
11
+
12
+ def consume(key, secret)
13
+ self.create_consumer(key, secret)
14
+ self.request_token = self.consumer.get_request_token
15
+ self.store.find(user).update(:consumer_key => key, :consumer_secret => secret)
16
+ self.request_token
17
+ end
18
+
19
+ def activate
20
+ if self.request_token
21
+ self.access_token = self.request_token.get_access_token
22
+ self.store.find(user).update(:access_key => self.access_token.token, :access_secret => self.access_token.secret)
23
+ end
24
+ end
25
+
26
+ def create_consumer(key, secret)
27
+ self.consumer = OAuth::Consumer.new(key, secret, { :site => "http://boomloop.com" })
28
+ end
29
+
30
+ def create_accesstoken
31
+ credentials = self.store.find(self.user)
32
+ self.consumer ||= create_consumer(credentials['consumer_key'], credentials['consumer_secret'])
33
+ self.access_token ||= OAuth::AccessToken.new(self.consumer, credentials['access_key'], credentials['access_secret'])
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Boomloop
2
+ module Authentication
3
+ class Credentials
4
+ attr_accessor :username, :store, :options
5
+
6
+ def initialize(username, store, options)
7
+ self.username = username
8
+ self.store = store
9
+ self.options = options || {}
10
+ end
11
+
12
+ def update(tosave)
13
+ tosave.each do |key, value|
14
+ self.options[key] = value
15
+ end
16
+
17
+ save
18
+ end
19
+
20
+ def save
21
+ self.store.update(self)
22
+ end
23
+
24
+ def [](key)
25
+ self.options[key]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ module Boomloop
2
+ module Authentication
3
+ module Store
4
+ class Base
5
+ def update(credentials)
6
+ raise NotImplementedError.new("where's me store!")
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ module Boomloop
2
+ module Authentication
3
+ module Store
4
+ class YAMLStore < Base
5
+ @@ymlfile = File.dirname(__FILE__) + '/../../../config/credentials.yml'
6
+
7
+ class << self
8
+ attr_accessor :config
9
+ end
10
+
11
+ def initialize
12
+ self.class.load_config
13
+ end
14
+
15
+ def self.load_config
16
+ File.open(@@ymlfile) do |file|
17
+ self.config = YAML.load(file) || {}
18
+ end
19
+ end
20
+
21
+ def self.save_config
22
+ if self.config
23
+ File.open(@@ymlfile, "w") do |f|
24
+ f.write self.config.to_yaml
25
+ end
26
+ end
27
+ end
28
+
29
+ def update(credentials)
30
+ self.class.config[credentials.username] = credentials.options
31
+ self.class.save_config
32
+ end
33
+
34
+ def find(user)
35
+ ::Boomloop::Authentication::Credentials.new(user, self, self.class.config[user])
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/boomloop.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'yaml'
3
+ gem 'oauth'
4
+ require 'oauth/consumer'
5
+ require 'ostruct'
6
+ require 'activesupport'
7
+
8
+ module Boomloop
9
+ class ApiError < ::StandardError; end
10
+ end
11
+
12
+ Dir.glob(File.dirname(__FILE__) + "/**/*.rb").each do |file|
13
+ require file
14
+ end
@@ -0,0 +1,84 @@
1
+ module Boomloop
2
+ module Resources
3
+ class Base < ::OpenStruct
4
+ API_BASE = 'http://api.boomloop.com/'
5
+
6
+ class << self
7
+ attr_accessor :connection
8
+ end
9
+
10
+ def self.connection
11
+ @@connection ||= init
12
+ end
13
+
14
+ # get oauth token
15
+ def self.init
16
+ client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
17
+ self.connection = client.create_accesstoken
18
+ end
19
+
20
+ def save
21
+ returned = self.class.create(self)
22
+ self.instance_variable_set("@table", returned.to_hash)
23
+ returned
24
+ end
25
+
26
+ def child_resources
27
+ links = to_hash.keys.select { |key| key =~ /resource-url$/ }
28
+ end
29
+
30
+ def to_hash
31
+ instance_variable_get("@table")
32
+ end
33
+
34
+ def to_xml
35
+ self.to_hash.to_xml
36
+ end
37
+
38
+ def self.singular
39
+ self.to_s.demodulize.tableize.singularize
40
+ end
41
+
42
+ def self.plural
43
+ self.to_s.demodulize.pluralize.tableize
44
+ end
45
+
46
+ # REST methods
47
+ def self.index(params = {})
48
+ url = API_BASE + self.plural
49
+ url += "?#{ params.to_query }" unless params.empty?
50
+ xml = connection.get(url)
51
+ attrs = Hash.from_xml(xml)
52
+ construct_resource_collection(attrs)
53
+ end
54
+
55
+ def self.show(url)
56
+ xml = connection.get(url)
57
+ attrs = Hash.from_xml(xml)
58
+ self.new(attrs[self.singular])
59
+ end
60
+
61
+ def self.create(resource)
62
+ url = API_BASE + self.plural
63
+ xml = connection.post(url, resource.to_hash.to_query)
64
+ self.new(Hash.from_xml(xml)[self.singular])
65
+ end
66
+
67
+ def self.construct_resource_collection(attrs)
68
+ collection = attrs[self.plural][self.singular]
69
+ case collection
70
+ when Array : collection.map { |hash| self.new(hash) }
71
+ when Hash : self.new(collection)
72
+ end
73
+ end
74
+
75
+ def self.transitive_create(resource)
76
+ if resource.child_resources
77
+ child_resources.each { |child| transitive_create(child) }
78
+ else
79
+ create(resource)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,6 @@
1
+ module Boomloop
2
+ module Resources
3
+ class Event < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Boomloop
2
+ module Resources
3
+ class EventSeries < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Boomloop
2
+ module Resources
3
+ class Place < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Boomloop
2
+ module Resources
3
+ class TicketCategory < Base
4
+ end
5
+ end
6
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Boomloop #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,105 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ context "a boomloop resource" do
4
+ setup do
5
+ @connection = Boomloop::Resources::Base.connection
6
+ end
7
+
8
+ specify "should be creatable by passing in a hash of values" do
9
+ monster = Boomloop::Resources::Monster.new(:size => :huge, :affect => :sanguine, :name => "fred")
10
+ monster.affect.should.be :sanguine
11
+ end
12
+
13
+ specify "should be able to return a hash representation of itself" do
14
+ qualities = { :size => :huge, :affect => :sanguine, :name => "fred" }
15
+ monster = Boomloop::Resources::Monster.new(qualities)
16
+ monster.to_hash.should.equal qualities
17
+ end
18
+
19
+ specify "should be showable when calling Boomloop::Resources::Monster.show('http://api.boomloop.com/monsters/fred')" do
20
+ @connection.expects(:get).with("http://api.boomloop.com/monsters/fred").at_least_once.returns(%Q[
21
+ <monster>
22
+ <resource_url>http://api.boomloop.com/monsters/fred</resource_url>
23
+ <size>huge</size>
24
+ <affect>sanguine</affect>
25
+ <name>fred</name>
26
+ </monster>
27
+ ])
28
+
29
+ monster = Boomloop::Resources::Monster.show('http://api.boomloop.com/monsters/fred')
30
+ monster.name.should.equal "fred"
31
+ end
32
+
33
+ specify "should be listable when calling Boomloop::Resources::Monster.index" do
34
+ @connection.expects(:get).with("http://api.boomloop.com/monsters").at_least_once.returns(%Q[
35
+ <monsters>
36
+ <monster>
37
+ <resource_url>http://api.boomloop.com/monsters/fred</resource_url>
38
+ <size>huge</size>
39
+ <affect>sanguine</affect>
40
+ <name>fred</name>
41
+ </monster>
42
+
43
+ <monster>
44
+ <resource_url>http://api.boomloop.com/monsters/simon</resource_url>
45
+ <size>middling</size>
46
+ <affect>indifferent</affect>
47
+ <name>simon</name>
48
+ </monster>
49
+ </monsters>
50
+ ])
51
+
52
+ monsters = Boomloop::Resources::Monster.index
53
+ monsters.map { |monster| monster.name }.should.include "fred"
54
+ end
55
+
56
+ specify "should be listable when calling Boomloop::Resources::Monster.index and there is only one result" do
57
+ @connection.expects(:get).with("http://api.boomloop.com/monsters").at_least_once.returns(%Q[
58
+ <monsters>
59
+ <monster>
60
+ <resource_url>http://api.boomloop.com/monsters/fred</resource_url>
61
+ <size>huge</size>
62
+ <affect>sanguine</affect>
63
+ <name>fred</name>
64
+ </monster>
65
+ </monsters>
66
+ ])
67
+
68
+ monsters = Boomloop::Resources::Monster.index
69
+ monsters.name.should.equal "fred"
70
+ end
71
+
72
+ specify "should be listable with attributes when calling Boomloop::Resources::Monster.index(:affect => :sanguine)" do
73
+ @connection.expects(:get).with("http://api.boomloop.com/monsters?affect=sanguine").at_least_once.returns(%Q[
74
+ <monsters>
75
+ <monster>
76
+ <resource_url>http://api.boomloop.com/monsters/fred</resource_url>
77
+ <size>huge</size>
78
+ <affect>sanguine</affect>
79
+ <name>fred</name>
80
+ </monster>
81
+ </monsters>
82
+ ])
83
+
84
+ monsters = Boomloop::Resources::Monster.index(:affect => :sanguine)
85
+ monsters.name.should.equal "fred"
86
+ end
87
+
88
+ specify "should be savable when calling .save on a Monster instance" do
89
+ intended_resource_url = 'http://api.boomloop.com/monsters/samuel'
90
+ intended_attributes = { :size => :laughable, :affect => :mordant, :name => "samuel" }
91
+
92
+ @connection.expects(:post).with("http://api.boomloop.com/monsters", intended_attributes.to_query).at_least_once.returns(%Q[
93
+ <monster>
94
+ <resource_url>#{ intended_resource_url }</resource_url>
95
+ <size>laughable</size>
96
+ <affect>mordant</affect>
97
+ <name>samuel</name>
98
+ </monster>
99
+ ])
100
+
101
+ monster = Boomloop::Resources::Monster.new(intended_attributes)
102
+ monster.save
103
+ monster.resource_url.should.equal intended_resource_url
104
+ end
105
+ end
@@ -0,0 +1,6 @@
1
+ module Boomloop
2
+ module Resources
3
+ class Monster < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'test/spec'
3
+ require 'mocha'
4
+
5
+ current_dir = File.dirname(__FILE__)
6
+
7
+ require current_dir + '/../lib/boomloop'
8
+ require current_dir + '/mocks/monster'
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: purzelrakete-boomloop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Rany Keddo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-21 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: oauth
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.0
23
+ version:
24
+ description: boomloop is a kick-ass event platform.
25
+ email: rany@playtype.net
26
+ executables:
27
+ - boomloop
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - History.txt
32
+ - README.txt
33
+ files:
34
+ - lib/authentication/client.rb
35
+ - lib/authentication/credentials.rb
36
+ - lib/authentication/store/base.rb
37
+ - lib/authentication/store/yaml_store.rb
38
+ - lib/boomloop.rb
39
+ - lib/resources/base.rb
40
+ - lib/resources/event.rb
41
+ - lib/resources/event_series.rb
42
+ - lib/resources/place.rb
43
+ - lib/resources/ticket_category.rb
44
+ - lib/version.rb
45
+ - bin/boomloop
46
+ - History.txt
47
+ - README.txt
48
+ - test/boomloop_resource_test.rb
49
+ - test/mocks
50
+ - test/mocks/monster.rb
51
+ - test/test_helper.rb
52
+ - config/credentials.yml
53
+ has_rdoc: true
54
+ homepage: http://github.com/purzelrakete/boomloop
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.txt
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.0.1
77
+ signing_key:
78
+ specification_version: 2
79
+ summary: Ruby API for boomloop.com
80
+ test_files: []
81
+