twitter_server 0.1.0

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 rick
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.
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = twitter_server
2
+
3
+ This is an attempt at a Twitter API implementation on top of Sinatra. This is
4
+ for all the people that experience Twitter purely through one or more of the
5
+ great clients on top of it.
6
+
7
+ SUPER alpha, ruby API will probably change!
8
+
9
+ == USAGE
10
+
11
+ The public API that you should be concerned with is the Sinatra API. Similar
12
+ to how Sinatra lets you respond to HTTP requests, this lets you respond to
13
+ Twitter requests
14
+
15
+ require 'sinatra'
16
+ require 'twitter_server'
17
+
18
+ get '/' do
19
+ 'hello world'
20
+ end
21
+
22
+ twitter_statuses_home_timeline do |params|
23
+ ...
24
+ end
25
+
26
+ The Sinatra Extension API is used, so you can also create separate Sinatra
27
+ classes and mount them separately.
28
+
29
+ require 'sinatra/base'
30
+ require 'twitter_server'
31
+
32
+ class MyTwitterApp < Sinatra::Base
33
+ register Sinatra::TwitterServer
34
+
35
+ get '/' do
36
+ 'hello world'
37
+ end
38
+
39
+ twitter_statuses_home_timeline do |params|
40
+ ...
41
+ end
42
+ end
43
+
44
+ == IDEAS
45
+
46
+ * Wrap a blogging service (see Wordpress, Tumblr)
47
+ * Get up-to-date event notifications on internal systems
48
+ * Uh yes, clone Twitter. You can probably rewrite it in a weekend :)
49
+
50
+ See demo/faker_server.rb for an in-memory, randomly generated, read-only
51
+ twitter server.
52
+
53
+ == TODO
54
+
55
+ * Everything on http://apiwiki.twitter.com/Twitter-API-Documentation that's
56
+ not implemented
57
+ * XML/JSON parsing
58
+ * Better XML/JSON/ATOM/RSS rendering
59
+ * handle basic auth and oauth
60
+ * cleanup pluggable renderers
61
+ * gem packaging
62
+
63
+ == Note on Patches/Pull Requests
64
+
65
+ * Fork the project.
66
+ * Make your feature addition or bug fix.
67
+ * Add tests for it. This is important so I don't break it in a
68
+ future version unintentionally.
69
+ * Commit, do not mess with rakefile, version, or history.
70
+ (if you want to have your own version, that is fine but bump version in a
71
+ commit by itself I can ignore when I pull)
72
+ * Send me a pull request. Bonus points for topic branches.
73
+
74
+ == Copyright
75
+
76
+ Copyright (c) 2009 rick. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "twitter_server"
8
+ gem.summary = %Q{Twitter API implementation on top of Sinatra}
9
+ gem.description = %Q{Twitter API implementation on top of Sinatra}
10
+ gem.email = "technoweenie@gmail.com"
11
+ gem.homepage = "http://github.com/technoweenie/twitter_server"
12
+ gem.authors = ["technoweenie"]
13
+ gem.add_development_dependency "context", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "twitter_server #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'sinatra'
3
+ require 'twitter_server'
4
+ require 'faker'
5
+ require 'active_support'
6
+
7
+ TwitterServer.xml_renderer = TwitterServer::Renderer::NokogiriRenderer
8
+
9
+ $user = {:id => 1, :name => Faker::Name.name}
10
+ $friend = {:id => 2, :name => Faker::Name.name}
11
+ $statuses = {
12
+ $user => [
13
+ {:id => 1, :text => 'oh hai', :source => 'api'},
14
+ {:id => 2, :text => 'lol wut', :source => 'api', :source_href => 'http://google.com'}
15
+ ],
16
+ $friend => [
17
+ {:id => 3, :text => 'oh hai', :source => 'api'}
18
+ ]
19
+ }
20
+
21
+ $users = [$user, $friend]
22
+ $users.each { |u| u[:screen_name] = u[:name].underscore }
23
+ $statuses.each do |user, statuses|
24
+ statuses.each { |st| st[:user] = user }
25
+ end
26
+
27
+ $user_id_index = $users.inject({}) { |memo, user| memo.update(user[:id] => user) }
28
+ $screen_name_index = $users.inject({}) { |memo, user| memo.update(user[:screen_name] => user) }
29
+
30
+ twitter_help
31
+
32
+ twitter_statuses_home_timeline do |params|
33
+ $statuses.values.flatten
34
+ end
35
+
36
+ twitter_statuses_friends_timeline do |params|
37
+ $statuses.values.flatten
38
+ end
39
+
40
+ twitter_statuses_user_timeline do |params|
41
+ user = params[:user_id] == '1' ? $user : $friend
42
+ $statuses[user]
43
+ end
44
+
45
+ twitter_users_show do |params|
46
+ if user_id = (params[:id] || params[:user_id])
47
+ $user_id_index[user_id]
48
+ elsif params[:screen_name]
49
+ $screen_name_index[params[:screen_name]]
50
+ end
51
+ end
52
+
53
+ twitter_account_verify_credentials do |params|
54
+ $user.merge(:status => $statuses[$user].first)
55
+ end
@@ -0,0 +1,92 @@
1
+ require 'nokogiri'
2
+ module TwitterServer
3
+ module Renderer
4
+ # Base Renderer classes should possibly store schemas for the objects (status, user, etc).
5
+ # Do some basic ruby type conversions for the format the api expects.
6
+ class NokogiriRenderer
7
+ def initialize(root)
8
+ @xml = Nokogiri::XML::Builder.new
9
+ node(root) { yield self }
10
+ end
11
+
12
+ def node(key)
13
+ r = self
14
+ @xml.send key do
15
+ yield r
16
+ end
17
+ end
18
+
19
+ def to_s
20
+ @xml.to_xml
21
+ end
22
+
23
+ # <id>1401881</id>
24
+ # <name>Doug Williams</name>
25
+ # <screen_name>dougw</screen_name>
26
+ # <location>San Francisco, CA</location>
27
+ # <description>Twitter API Support. Internet, greed, users, dougw and opportunities are my passions.</description>
28
+ # <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/59648642/avatar_normal.png</profile_image_url>
29
+ # <url>http://www.igudo.com</url>
30
+ # <protected>false</protected>
31
+ # <followers_count>1031</followers_count>
32
+ # <profile_background_color>9ae4e8</profile_background_color>
33
+ # <profile_text_color>000000</profile_text_color>
34
+ # <profile_link_color>0000ff</profile_link_color>
35
+ # <profile_sidebar_fill_color>e0ff92</profile_sidebar_fill_color>
36
+ # <profile_sidebar_border_color>87bc44</profile_sidebar_border_color>
37
+ # <friends_count>293</friends_count>
38
+ # <created_at>Sun Mar 18 06:42:26 +0000 2007</created_at>
39
+ # <favourites_count>0</favourites_count>
40
+ # <utc_offset>-18000</utc_offset>
41
+ # <time_zone>Eastern Time (US & Canada)</time_zone>
42
+ # <profile_background_image_url>http://s3.amazonaws.com/twitter_production/profile_background_images/2752608/twitter_bg_grass.jpg</profile_background_image_url>
43
+ # <profile_background_tile>false</profile_background_tile>
44
+ # <statuses_count>3390</statuses_count>
45
+ # <notifications>false</notifications>
46
+ # <following>false</following>
47
+ # <geo_enabled>true</geo_enabled> <!-- Not yet part of the current payload. [COMING SOON] -->
48
+ # <verified>true</verified>
49
+ def user(user)
50
+ return if user.nil? || user.empty?
51
+ [:id, :name, :screen_name].each do |key|
52
+ @xml.send "#{key}_", user[key] if user.key?(key)
53
+ end
54
+ if user.key?(:status)
55
+ node(:status) do
56
+ status(user[:status])
57
+ end
58
+ end
59
+ end
60
+
61
+ # <created_at>Tue Apr 07 22:52:51 +0000 2009</created_at>
62
+ # <id>1472669360</id>
63
+ # <text>At least I can get your humor through tweets. RT @abdur: I don't mean this in a bad way, but genetically speaking your a cul-de-sac.</text>
64
+ # <source>&lt;a href="http://www.tweetdeck.com/">TweetDeck&lt;/a></source>
65
+ # <truncated>false</truncated>
66
+ # <in_reply_to_status_id></in_reply_to_status_id>
67
+ # <in_reply_to_user_id></in_reply_to_user_id>
68
+ # <favorited>false</favorited>
69
+ # <in_reply_to_screen_name></in_reply_to_screen_name>
70
+ def status(status)
71
+ return if status.nil? || status.empty?
72
+ [:id, :created_at, :text, :truncated, :in_reply_to_status_id, :in_reply_to_user_id, :favorited, :in_reply_to_screen_name].each do |key|
73
+ @xml.send("#{key}_", status[key]) if status.key?(key)
74
+ end
75
+ if status.key?(:user)
76
+ node :user do
77
+ user(status[:user])
78
+ end
79
+ end
80
+ if status.key?(:source)
81
+ if status.key?(:source_href)
82
+ node :source do
83
+ @xml.a(status[:source], :href => status[:source_href])
84
+ end
85
+ else
86
+ @xml.source status[:source]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,131 @@
1
+ require 'sinatra/base'
2
+
3
+ module TwitterServer
4
+ class << self
5
+ attr_writer :xml_renderer
6
+ end
7
+
8
+ # IDEA: have set renderers for JSON/XML/ATOM/RSS
9
+ # Then Sinatra::TwitterServer::Helpers only has a single render method
10
+ # that delegates to the given renderer for the request format.
11
+ # Assume the renderers know how to do their thing.
12
+ def self.xml_renderer
13
+ @xml_renderer || Renderer::NokogiriRenderer
14
+ end
15
+
16
+ module Renderer
17
+ autoload :NokogiriRenderer, 'renderers/nokogiri_renderer'
18
+ end
19
+ end
20
+
21
+ module Sinatra
22
+ module TwitterServer
23
+ module Helpers
24
+ def api_options(*keys)
25
+ keys.inject({}) do |memo, key|
26
+ params.include?(key.to_s) ? memo.update(key => params[key]) : memo
27
+ end
28
+ end
29
+
30
+ def render_xml_statuses(statuses)
31
+ render_xml(:statuses) do |r|
32
+ statuses.each do |st|
33
+ r.node(:status) do
34
+ r.status(st)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def render_xml_user(user)
41
+ render_xml(:user) do |r|
42
+ r.user(user)
43
+ end
44
+ end
45
+
46
+ def render_xml(root)
47
+ ::TwitterServer.xml_renderer.new(root) do |renderer|
48
+ yield renderer
49
+ end.to_s
50
+ end
51
+ end
52
+
53
+ def self.registered(app)
54
+ app.helpers Sinatra::TwitterServer::Helpers
55
+ end
56
+
57
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-home_timeline
58
+ def twitter_statuses_home_timeline
59
+ get "/statuses/home_timeline.:format" do
60
+ options = api_options(:since_id, :max_id, :count, :page)
61
+ format = params[:format]
62
+ statuses = yield options
63
+ render_xml_statuses(statuses)
64
+ end
65
+ end
66
+
67
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-friends_timeline
68
+ def twitter_statuses_friends_timeline
69
+ get "/statuses/friends_timeline.:format" do
70
+ options = api_options(:since_id, :max_id, :count, :page)
71
+ format = params[:format]
72
+ statuses = yield options
73
+ render_xml_statuses(statuses)
74
+ end
75
+ end
76
+
77
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-user_timeline
78
+ def twitter_statuses_user_timeline
79
+ get "/statuses/user_timeline.:format" do
80
+ options = api_options(:user_id, :screen_name, :since_id, :max_id, :count, :page)
81
+ format = params[:format]
82
+ statuses = yield options
83
+ render_xml_statuses(statuses)
84
+ end
85
+
86
+ get "/statuses/user_timeline/:id.:format" do
87
+ options = api_options(:id, :user_id, :screen_name, :since_id, :max_id, :count, :page)
88
+ format = params[:format]
89
+ statuses = yield options
90
+ render_xml_statuses(statuses)
91
+ end
92
+ end
93
+
94
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-users%C2%A0show
95
+ def twitter_users_show
96
+ get "/users/show.:format" do
97
+ options = api_options(:user_id, :screen_name)
98
+ format = params[:format]
99
+ user = yield options
100
+ render_xml_user(user)
101
+ end
102
+
103
+ get "/users/show/:id.:format" do
104
+ options = api_options(:id)
105
+ format = params[:format]
106
+ user = yield options
107
+ render_xml_user(user)
108
+ end
109
+ end
110
+
111
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-account%C2%A0verify_credentials
112
+ def twitter_account_verify_credentials
113
+ get "/account/verify_credentials.:format" do
114
+ format = params[:format]
115
+ user = yield
116
+ render_xml_user(user)
117
+ end
118
+ end
119
+
120
+ # http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-help%C2%A0test
121
+ HELP_XML_RESPONSE = '<ok>true</ok>'.freeze
122
+ HELP_RESPONSE = 'ok'.freeze
123
+ def twitter_help
124
+ get "/help/test.:format" do
125
+ params[:format] == 'xml' ? HELP_XML_RESPONSE : HELP_RESPONSE
126
+ end
127
+ end
128
+ end
129
+
130
+ register TwitterServer
131
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'context'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'rack/test'
8
+ require 'twitter_server'
9
+
10
+ module TwitterServer
11
+ class TestCase < Test::Unit::TestCase
12
+ include Rack::Test::Methods
13
+
14
+ def assert_xml(actual = nil)
15
+ xml = Nokogiri::XML::Builder.new
16
+ yield xml
17
+ expected = xml.to_xml
18
+ actual ||= last_response.body
19
+ assert_equal expected, actual, "EXPECTED\n#{expected}\nACTUAL\n#{actual}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
2
+
3
+ class ApiAccountTest < TwitterServer::TestCase
4
+ class AccountApp < Sinatra::Base
5
+ register Sinatra::TwitterServer
6
+
7
+ twitter_account_verify_credentials { {:id => 1} }
8
+ twitter_users_show { |params| {:id => 1, :screen_name => params.inspect, :status => {:text => 'holla'}} }
9
+ end
10
+
11
+ def app
12
+ AccountApp
13
+ end
14
+
15
+ describe "account/verify credentials" do
16
+ it "returns user xml" do
17
+ get '/account/verify_credentials.xml'
18
+ assert_xml do |xml|
19
+ xml.user do
20
+ xml.id_ 1
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "users/show" do
27
+ it "returns user xml from given id" do
28
+ get "/users/show/123.xml"
29
+ assert_xml do |xml|
30
+ xml.user do
31
+ xml.id_ 1
32
+ xml.screen_name %({:id=>"123"})
33
+ xml.status do
34
+ xml.text_ "holla"
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ it "returns user xml from given user_id" do
41
+ get "/users/show.xml?user_id=456"
42
+ assert_xml do |xml|
43
+ xml.user do
44
+ xml.id_ 1
45
+ xml.screen_name %({:user_id=>"456"})
46
+ xml.status do
47
+ xml.text_ "holla"
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ it "returns user xml from given screen_name" do
54
+ get "/users/show.xml?screen_name=789"
55
+ assert_xml do |xml|
56
+ xml.user do
57
+ xml.id_ 1
58
+ xml.screen_name %({:screen_name=>"789"})
59
+ xml.status do
60
+ xml.text_ "holla"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
2
+
3
+ class ApiHelpTest < TwitterServer::TestCase
4
+ class HelpApp < Sinatra::Base
5
+ register Sinatra::TwitterServer
6
+
7
+ twitter_help
8
+ end
9
+
10
+ def app
11
+ HelpApp
12
+ end
13
+
14
+ it "returns 'Ok' for :xml format" do
15
+ get '/help/test.xml'
16
+ assert_equal Sinatra::TwitterServer::HELP_XML_RESPONSE, last_response.body
17
+ end
18
+
19
+ it "returns 'Ok' for :json format" do
20
+ get '/help/test.json'
21
+ assert_equal Sinatra::TwitterServer::HELP_RESPONSE, last_response.body
22
+ end
23
+ end
@@ -0,0 +1,130 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
2
+
3
+ class ApiStatusesTest < TwitterServer::TestCase
4
+ class StatusesApp < Sinatra::Base
5
+ register Sinatra::TwitterServer
6
+
7
+
8
+ resp = lambda do |params|
9
+ user = {:id => 1, :screen_name => 'user'}
10
+ statuses = []
11
+ [:id, :user_id, :screen_name, :since_id, :max_id, :count, :page].each do |key|
12
+ statuses << {:text => "#{key}=#{params[key]}", :user => user}
13
+ end
14
+ statuses
15
+ end
16
+ twitter_statuses_home_timeline &resp
17
+ twitter_statuses_friends_timeline &resp
18
+ twitter_statuses_user_timeline &resp
19
+ end
20
+
21
+ def app
22
+ StatusesApp
23
+ end
24
+
25
+ describe "user timeline" do
26
+ it "requests without :id return statuses xml" do
27
+ get "/statuses/user_timeline.xml?user_id=1&screen_name=2&since_id=3&max_id=4&count=5&page=6"
28
+ assert_xml do |xml|
29
+ xml.statuses do
30
+ xml.status do
31
+ xml.text_ "id="
32
+ xml.user do
33
+ xml.id_ 1
34
+ xml.screen_name 'user'
35
+ end
36
+ end
37
+ [:user_id, :screen_name, :since_id, :max_id, :count, :page].each_with_index do |key, idx|
38
+ xml.status do
39
+ xml.text_ "#{key}=#{idx+1}"
40
+ xml.user do
41
+ xml.id_ 1
42
+ xml.screen_name 'user'
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ it "requests with :id return statuses xml" do
51
+ get "/statuses/user_timeline/bob.xml?user_id=1&screen_name=2&since_id=3&max_id=4&count=5&page=6"
52
+ assert_xml do |xml|
53
+ xml.statuses do
54
+ xml.status do
55
+ xml.text_ "id=bob"
56
+ xml.user do
57
+ xml.id_ 1
58
+ xml.screen_name 'user'
59
+ end
60
+ end
61
+ [:user_id, :screen_name, :since_id, :max_id, :count, :page].each_with_index do |key, idx|
62
+ xml.status do
63
+ xml.text_ "#{key}=#{idx+1}"
64
+ xml.user do
65
+ xml.id_ 1
66
+ xml.screen_name 'user'
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "home timeline" do
76
+ it "returns statuses xml" do
77
+ get "/statuses/home_timeline.xml?since_id=1&max_id=2&count=3&page=4"
78
+ assert_xml do |xml|
79
+ xml.statuses do
80
+ [:id, :user_id, :screen_name].each do |key|
81
+ xml.status do
82
+ xml.text_ "#{key}="
83
+ xml.user do
84
+ xml.id_ 1
85
+ xml.screen_name 'user'
86
+ end
87
+ end
88
+ end
89
+ [:since_id, :max_id, :count, :page].each_with_index do |key, idx|
90
+ xml.status do
91
+ xml.text_ "#{key}=#{idx+1}"
92
+ xml.user do
93
+ xml.id_ 1
94
+ xml.screen_name 'user'
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "friends timeline" do
104
+ it "returns statuses xml" do
105
+ get "/statuses/friends_timeline.xml?since_id=1&max_id=2&count=3&page=4"
106
+ assert_xml do |xml|
107
+ xml.statuses do
108
+ [:id, :user_id, :screen_name].each do |key|
109
+ xml.status do
110
+ xml.text_ "#{key}="
111
+ xml.user do
112
+ xml.id_ 1
113
+ xml.screen_name 'user'
114
+ end
115
+ end
116
+ end
117
+ [:since_id, :max_id, :count, :page].each_with_index do |key, idx|
118
+ xml.status do
119
+ xml.text_ "#{key}=#{idx+1}"
120
+ xml.user do
121
+ xml.id_ 1
122
+ xml.screen_name 'user'
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,60 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{twitter_server}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["technoweenie"]
12
+ s.date = %q{2009-12-19}
13
+ s.description = %q{Twitter API implementation on top of Sinatra}
14
+ s.email = %q{technoweenie@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "demo/faker_server.rb",
27
+ "lib/renderers/nokogiri_renderer.rb",
28
+ "lib/twitter_server.rb",
29
+ "test/helper.rb",
30
+ "test/sinatra/account_test.rb",
31
+ "test/sinatra/help_test.rb",
32
+ "test/sinatra/statuses_test.rb",
33
+ "twitter_server.gemspec"
34
+ ]
35
+ s.homepage = %q{http://github.com/technoweenie/twitter_server}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{Twitter API implementation on top of Sinatra}
40
+ s.test_files = [
41
+ "test/helper.rb",
42
+ "test/sinatra/account_test.rb",
43
+ "test/sinatra/help_test.rb",
44
+ "test/sinatra/statuses_test.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<context>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<context>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<context>, [">= 0"])
58
+ end
59
+ end
60
+
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twitter_server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - technoweenie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-19 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: context
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Twitter API implementation on top of Sinatra
26
+ email: technoweenie@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - demo/faker_server.rb
42
+ - lib/renderers/nokogiri_renderer.rb
43
+ - lib/twitter_server.rb
44
+ - test/helper.rb
45
+ - test/sinatra/account_test.rb
46
+ - test/sinatra/help_test.rb
47
+ - test/sinatra/statuses_test.rb
48
+ - twitter_server.gemspec
49
+ has_rdoc: true
50
+ homepage: http://github.com/technoweenie/twitter_server
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Twitter API implementation on top of Sinatra
77
+ test_files:
78
+ - test/helper.rb
79
+ - test/sinatra/account_test.rb
80
+ - test/sinatra/help_test.rb
81
+ - test/sinatra/statuses_test.rb