radiant-twitter-extension 2.0.0.rc1

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/HELP_admin.md ADDED
@@ -0,0 +1,19 @@
1
+ You can have updates to your site automatically send details to your
2
+ Twitter account. All you'll need to do is provide your account information
3
+ in the Radiant::Config settings.
4
+
5
+ The required keys are `twitter.password`, `twitter.username` and `twitter.url_host`.
6
+
7
+ The `username` and `password` are the same for your login details of your Twitter
8
+ account. The `url_host` will be used when generating links back to your site, this
9
+ should be your domain name.
10
+
11
+ On the edit screen of each page, you can select the option to notify Twitter
12
+ of all of the updates to the children of that page. You can create a blog page,
13
+ for example, and have each new post linked in your Twitter account.
14
+
15
+ _Built with version `0.6.6` of the `twitter` gem._
16
+
17
+ To get latest tweet(s):
18
+
19
+ <r:twitter:message [ max="10" ] />
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Twitter
2
+
3
+ An extension to Radiant that will automatically tweet the publication of new pages in selected parts of your site, and which provides a set of radius tags that allow you to feature twitter feeds of different kinds on your site.
4
+
5
+ ## Installation
6
+
7
+ sudo gem install radiant-twitter-extension
8
+
9
+ add this to your environment.rb
10
+
11
+ config.gem 'radiant-twitter-extension', :version => '~> 2.0.0.rc1'
12
+
13
+ and then:
14
+
15
+ rake radiant:extensions:update_all
16
+ rake radiant:extensions:twitter:migrate
17
+
18
+ You can also vendor the extension in the old-fashioned way:
19
+
20
+ git submodule add git://github.com/radiant/radiant-twitter-extension.git vendor/extensions/twitter
21
+ rake radiant:extensions:twitter:update
22
+ rake radiant:extensions:twitter:migrate
23
+
24
+ ## Status
25
+
26
+ Nearly stable. I've just made some quite sweeping changes to bring this up to date, so small bugs are likely. Please file issues.
27
+
28
+ ## Configuration
29
+
30
+ You can present twitter searches and feeds without authenticating, but if you want to post automatically to twitter you need to provide login information. The extension adds a 'twitter' block to the main radiant configuration interface: enter your screen name and password. Future versions may integrate with Twitter as an application but for now all we need is the ability to tweet.
31
+
32
+ ## Tweet on publication
33
+
34
+ To post a tweet every time you publish a blog entry, check the 'Notify Twitter of newly published child pages?' box on the parent blog page. The tweet will contain the title of the page and its url.
35
+
36
+ ## Display a twitter feed
37
+
38
+ If radiant is configured to tweet for you, all you need is this radius tag:
39
+
40
+ <r:twitter:tweets [max="10"] />
41
+
42
+ If it's not configured, or you want to display another user:
43
+
44
+ <r:twitter:tweets user="screen_name" />
45
+
46
+ To display a hashtag, or any other search:
47
+
48
+ <r:twitter:tweets search="#radiant" />
49
+
50
+ To display tweets from someone's list:
51
+
52
+ <r:twitter:tweets user="screen_name" list="list_name" />
53
+
54
+ The default presentation of tweets is exactly as [suggested by Twitter](https://dev.twitter.com/terms/display-guidelines) and if you include their widget script and the provided css it should all just work. If you want to present tweets differently, a range of more detailed radius tags is available. This is a slightly more compact format:
55
+
56
+ <r:twitter:tweets user="screen_name" />
57
+ <li class="tweet">
58
+ <r:tweet:avatar class="avatar" />
59
+ <r:tweet:user:screen_name />
60
+ <span class="block">
61
+ <r:tweet:text />
62
+ </span>
63
+ <span class="hidden">
64
+ <r:tweet:reply_link />
65
+ <r:tweet:retweet_link />
66
+ </span>
67
+ </li>
68
+ </r:twitter:tweets>
69
+
70
+ ## Scripts and styles
71
+
72
+ The quick way to format tweets nicely is to include the supplied sass in your site stylesheet. If you're using radiant's built-in stylesheet manager and working in Sass, you can keep everything in one file (and selectively override it) by including this line near the top:
73
+
74
+ @import 'twitter.sass'
75
+
76
+ You can also link to `/stylesheets/twitter.css` in the usual way.
77
+
78
+ The links created by radius tags here are all compatible with twitter's widgeting. To enable basic intent-based popups, just include this line in the head or at the foot of your layout:
79
+
80
+ <script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
81
+
82
+ ## Todo
83
+
84
+ * More gratifying twitter integration of admin
85
+ * Page field to edit tweet text before publication
86
+ * URL-shortener
87
+
88
+ ## Copyright and license
89
+
90
+ Originally created by Sean Cribbs and now the work of many hands, including:
91
+
92
+ * Jim Gay
93
+ * Edmund Haselwanter
94
+ * Anna Billstrom
95
+ * William Ross
96
+
97
+ Currently maintained by Will at spanner.org. Issues and comments on github, please:
98
+
99
+ https://github.com/radiant/radiant-twitter-extension/issues
100
+
101
+ Released under the same terms as Rails and/or Radiant.
102
+
103
+
104
+
data/Rakefile ADDED
@@ -0,0 +1,120 @@
1
+ # I think this is the one that should be moved to the extension Rakefile template
2
+
3
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
4
+ # Check to see if the rspec plugin is installed first and require
5
+ # it if it is. If not, use the gem version.
6
+
7
+ # Determine where the RSpec plugin is by loading the boot
8
+ unless defined? RADIANT_ROOT
9
+ ENV["RAILS_ENV"] = "test"
10
+ case
11
+ when ENV["RADIANT_ENV_FILE"]
12
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
13
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
14
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
15
+ else
16
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
17
+ end
18
+ end
19
+
20
+ require 'rake'
21
+ require 'rake/rdoctask'
22
+ require 'rake/testtask'
23
+
24
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
25
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
26
+ require 'spec/rake/spectask'
27
+ # require 'spec/translator'
28
+
29
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
30
+ Object.send(:remove_const, :RADIANT_ROOT)
31
+
32
+ extension_root = File.expand_path(File.dirname(__FILE__))
33
+
34
+ task :default => :spec
35
+ task :stats => "spec:statsetup"
36
+
37
+ desc "Run all specs in spec directory"
38
+ Spec::Rake::SpecTask.new(:spec) do |t|
39
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
40
+ t.spec_files = FileList['spec/**/*_spec.rb']
41
+ end
42
+
43
+ namespace :spec do
44
+ desc "Run all specs in spec directory with RCov"
45
+ Spec::Rake::SpecTask.new(:rcov) do |t|
46
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
47
+ t.spec_files = FileList['spec/**/*_spec.rb']
48
+ t.rcov = true
49
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
50
+ end
51
+
52
+ desc "Print Specdoc for all specs"
53
+ Spec::Rake::SpecTask.new(:doc) do |t|
54
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
55
+ t.spec_files = FileList['spec/**/*_spec.rb']
56
+ end
57
+
58
+ [:models, :controllers, :views, :helpers].each do |sub|
59
+ desc "Run the specs under spec/#{sub}"
60
+ Spec::Rake::SpecTask.new(sub) do |t|
61
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
62
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
63
+ end
64
+ end
65
+
66
+ # Hopefully no one has written their extensions in pre-0.9 style
67
+ # desc "Translate specs from pre-0.9 to 0.9 style"
68
+ # task :translate do
69
+ # translator = ::Spec::Translator.new
70
+ # dir = RAILS_ROOT + '/spec'
71
+ # translator.translate(dir, dir)
72
+ # end
73
+
74
+ # Setup specs for stats
75
+ task :statsetup do
76
+ require 'code_statistics'
77
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
78
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
79
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
80
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
81
+ ::CodeStatistics::TEST_TYPES << "Model specs"
82
+ ::CodeStatistics::TEST_TYPES << "View specs"
83
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
84
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
85
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
86
+ end
87
+
88
+ namespace :db do
89
+ namespace :fixtures do
90
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
91
+ task :load => :environment do
92
+ require 'active_record/fixtures'
93
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
94
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
95
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ desc 'Generate documentation for the twitter extension.'
103
+ Rake::RDocTask.new(:rdoc) do |rdoc|
104
+ rdoc.rdoc_dir = 'rdoc'
105
+ rdoc.title = 'TwitterExtension'
106
+ rdoc.options << '--line-numbers' << '--inline-source'
107
+ rdoc.rdoc_files.include('README')
108
+ rdoc.rdoc_files.include('lib/**/*.rb')
109
+ end
110
+
111
+ # For extensions that are in transition
112
+ desc 'Test the twitter extension.'
113
+ Rake::TestTask.new(:test) do |t|
114
+ t.libs << 'lib'
115
+ t.pattern = 'test/**/*_test.rb'
116
+ t.verbose = true
117
+ end
118
+
119
+ # Load any custom rakefiles for extension
120
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,6 @@
1
+ %fieldset
2
+ %h4= t('twitter_extension.twitter')
3
+ %p= edit_config 'twitter.username'
4
+ %p= edit_config 'twitter.password'
5
+ %p= edit_config 'twitter.token'
6
+ %p= edit_config 'twitter.secret'
@@ -0,0 +1,5 @@
1
+ %h4= t('twitter_extension.twitter')
2
+ %p.ruled= show_config 'twitter.username'
3
+ %p.ruled= show_config 'twitter.password'
4
+ %p.ruled= show_config 'twitter.token'
5
+ %p.ruled= show_config 'twitter.secret'
@@ -0,0 +1,9 @@
1
+ %tr
2
+ %th.label
3
+ Twitter
4
+ %td
5
+ - fields_for @page do |pf|
6
+ = pf.check_box :notify_twitter_of_children
7
+ = pf.label :notify_twitter_of_children
8
+ - if @page.twitter_id
9
+ = link_to "[#{@page.twitter_id}]", "http://twitter.com/#{Radiant::Config['twitter.username']}/status/#{@page.twitter_id}"
@@ -0,0 +1,8 @@
1
+ Radiant.config do |config|
2
+ config.namespace 'twitter' do |twit|
3
+ twit.define 'username', :default => '', :allow_blank => true
4
+ twit.define 'password', :default => '', :allow_blank => true
5
+ twit.define 'token', :default => '', :allow_blank => true
6
+ twit.define 'secret', :default => '', :allow_blank => true
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ page:
5
+ notify_twitter_of_children: "Notify Twitter of newly published child pages?"
6
+ config:
7
+ twitter:
8
+ username: "Username (for tweets)"
9
+ password: "Password (for tweets)"
10
+ token: "Application token"
11
+ secret: "Application secret"
12
+ date:
13
+ formats:
14
+ twitter: "%m %B"
15
+ twitter_extension:
16
+ favorite: "Favorite"
17
+ reply: "Reply"
18
+ retweet: "Retweet"
19
+ twitter: "Twitter"
20
+
@@ -0,0 +1,11 @@
1
+ class AddTwitterNotificationFields < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :pages, :notify_twitter_of_children, :boolean, :default => false
4
+ add_column :pages, :twitter_id, :string
5
+ end
6
+
7
+ def self.down
8
+ remove_column :pages, :notify_twitter_of_children
9
+ remove_column :pages, :twitter_id
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module RadiantTwitterExtension
2
+ VERSION = '2.0.0.rc1'
3
+ SUMMARY = %q{Twitter posting and radius tags for twitter feeds.}
4
+ DESCRIPTION = %q{Posts notification of pages to Twitter and provides radiius tags to display the results of twitter searches.}
5
+ URL = "http://github.com/ehaselwanter/radiant-twitter-extension"
6
+ AUTHORS = ["Sean Cribbs", "Edmund Haselwanter", "Jim Gay", "William Ross"]
7
+ EMAIL = ["radiant@radiantcms.org"]
8
+ end
@@ -0,0 +1,28 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :twitter do
4
+
5
+ desc "Runs the migration of the Twitter extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ TwitterExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ TwitterExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ desc "Copies public assets of the Twitter to the instance public/ directory."
16
+ task :update => :environment do
17
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
18
+ puts "Copying assets from TwitterExtension"
19
+ Dir[TwitterExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
20
+ path = file.sub(TwitterExtension.root, '')
21
+ directory = File.dirname(path)
22
+ mkdir_p RAILS_ROOT + directory
23
+ cp file, RAILS_ROOT + path
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ require 'twitter'
2
+ module TwitterNotification
3
+ def self.included(base)
4
+ base.class_eval {
5
+ after_save :notify_twitter
6
+ }
7
+ end
8
+
9
+ def notify_twitter
10
+ if parent
11
+ if published? && Radiant.configured? && parent.notify_twitter_of_children? && !self.twitter_id
12
+ title_length = 138 - absolute_url.length
13
+ message_title = title.length > title_length ? (title[0..title_length-4] + "...") : title
14
+ message = "#{message_title}: #{absolute_url}"
15
+ begin
16
+ httpauth = Twitter::HTTPAuth.new(Radiant.config['twitter.username'], Radiant.config['twitter.password'])
17
+ client = Twitter::Base.new(httpauth)
18
+ status = client.update(message, :source => "radianttwitternotifier")
19
+ # Don't trigger save callbacks
20
+ self.class.update_all({:twitter_id => status.id}, :id => self.id)
21
+ rescue Twitter::Error => e
22
+ logger.error "Twitter Notification failure: #{e.inspect}"
23
+ end
24
+ end
25
+ end
26
+ true
27
+ end
28
+
29
+ def absolute_url
30
+ if host = Radiant.config['site.host']
31
+ if host =~ /^http/
32
+ "#{host}#{self.url}"
33
+ else
34
+ "http://#{host}#{self.url}"
35
+ end
36
+ end
37
+ end
38
+
39
+ def Radiant.configured?
40
+ !%w(twitter.username twitter.password site.host).any? {|k| Radiant.config[k].blank? }
41
+ end
42
+
43
+ end
@@ -0,0 +1,406 @@
1
+ require 'twitter'
2
+
3
+ module TwitterTags
4
+ include ActionView::Helpers::DateHelper
5
+ include Radiant::Taggable
6
+ class TagError < StandardError; end
7
+
8
+ tag 'twitter' do |tag|
9
+ tag.expand
10
+ end
11
+
12
+ desc %{
13
+ Retrieve a list of tweets. The minimal default is to return the ten most recent tweets of the
14
+ Radiant.configured twitter user (that is, the person as whom radiant is set up to tweet).
15
+ For that, you can use just a single tag:
16
+
17
+ <pre><code><r:twitter:tweets /></code></pre>
18
+
19
+ or control the presentation of tweets in a more detailed way:
20
+
21
+ <r:twitter:tweets:each><r:tweet:user:screen_name /> : <r:tweet:text /></r:twitter:tweets:each>
22
+
23
+ You can also specify a search in various ways.
24
+
25
+ * Supply a `max` attribute to change the number of tweets displayed. Default is 10.
26
+ * Supply a `user` attribute to display tweets from a different username
27
+ * Supply a `list` attribute to display tweets from the named list (see also r:twitter:list for a shortcut)
28
+ * Supply a `search` attribute to show tweets containing that text (see also r:twitter:search for a shortcut)
29
+ You don't need to %escape the search string.
30
+ In a search query the user and list parameters will be ignored.
31
+
32
+ <pre><code>
33
+ <r:twitter:tweets user="spanner_org" max="2" />
34
+ <r:twitter:tweets search="#radiant" />
35
+ </code></pre>
36
+
37
+ }
38
+ tag 'twitter:tweets' do |tag|
39
+ tag.locals.tweets = fetch_and_cache_tweets(tag.attr.slice('user', 'max', 'search', 'list').symbolize_keys)
40
+ tag.double? ? tag.expand : tag.render('twitter:messages')
41
+ end
42
+
43
+ tag 'twitter:tweets:each' do |tag|
44
+ tag.locals.tweets ||= fetch_and_cache_tweets(tag.attr.slice('user', 'max', 'search', 'list').symbolize_keys)
45
+ tag.render('_tweets_list', tag.attr.dup, &tag.block)
46
+ end
47
+
48
+ desc %{
49
+ Fetches and loops through tweets matching the supplied search string. You don't need to %escape the search string.
50
+
51
+ <pre><code>
52
+ <r:twitter:search for="#radiant"><r:tweets:each>...</r:tweets:each></r:twitter:search>
53
+ <r:twitter:search for="rails cms" max="1">...</r:twitter:search>
54
+ <r:twitter:search for="somethinbg" max="20">...</r:twitter:search>
55
+ </code></pre>
56
+
57
+ Short form also works:
58
+
59
+ <pre><code><r:twitter:search for="#radiant" /></code></pre>
60
+
61
+ and you can go stright into a loop:
62
+
63
+ <pre><code><r:twitter:search:each for="#radiant">...</r:twitter:search:each></code></pre>
64
+ }
65
+ tag 'twitter:search' do |tag|
66
+ tag.locals.tweets = fetch_and_cache_tweets(:search => tag.attr['for']) if tag.attr.any?
67
+ tag.double? ? tag.expand : tag.render('twitter:messages')
68
+ end
69
+
70
+ tag 'twitter:search:each' do |tag|
71
+ tag.locals.tweets ||= fetch_and_cache_tweets(:search => tag.attr['for'])
72
+ tag.render('_tweets_list', tag.attr.dup, &tag.block)
73
+ end
74
+
75
+ desc %{
76
+ Fetches tweets from the specified list belonging to the specified (or default) user.
77
+
78
+ <pre><code><r:twitter:list list="listname" [user="username"] [max="10"] /></code></pre>
79
+
80
+ Short form also works:
81
+
82
+ <pre><code><r:twitter:list list="radiant" /></code></pre>
83
+
84
+ and you can go stright into a loop:
85
+
86
+ <pre><code><r:twitter:list:each list="radiant">...</r:twitter:list:each></code></pre>
87
+ }
88
+ tag 'twitter:list' do |tag|
89
+ tag.locals.tweets = fetch_and_cache_tweets(:user => tag.attr['user'], :max => tag.attr['max'], :list => tag.attr['list']) if tag.attr.any?
90
+ tag.double? ? tag.expand : tag.render('twitter:messages')
91
+ end
92
+
93
+ tag 'twitter:list:each' do |tag|
94
+ tag.locals.tweets ||= fetch_and_cache_tweets(:user => tag.attr['user'], :max => tag.attr['max'], :list => tag.attr['list'])
95
+ tag.render('_tweets_list', tag.attr.dup, &tag.block)
96
+ end
97
+
98
+ desc %{
99
+ Returns the number of tweets.
100
+ }
101
+ tag 'tweets:length' do |tag|
102
+ tag.render('_tweets_length', tag.attr.dup, &tag.block)
103
+ end
104
+ tag 'twitter:list:length' do |tag|
105
+ tag.render('_tweets_length', tag.attr.dup, &tag.block)
106
+ end
107
+ tag 'twitter:search:length' do |tag|
108
+ tag.render('_tweets_length', tag.attr.dup, &tag.block)
109
+ end
110
+
111
+ desc %{
112
+ Loops through the current list of tweets.
113
+ }
114
+ tag 'tweets:each' do |tag|
115
+ tag.render('_tweets_list', tag.attr.dup, &tag.block)
116
+ end
117
+
118
+ # these are just for drying out: they can't be called directly.
119
+
120
+ tag '_tweets_list' do |tag|
121
+ raise TagError, "tweet_list utility tag called without a list of tweets to list" unless tag.locals.tweets
122
+ out = ""
123
+ tag.locals.tweets.each do |tweet|
124
+ tag.locals.tweet = tweet
125
+ if tag.double?
126
+ out << tag.expand
127
+ else
128
+ out << tag.render('tweet:message')
129
+ end
130
+ end
131
+ out
132
+ end
133
+
134
+ tag '_tweets_length' do |tag|
135
+ raise TagError, "_tweets_length utility tag called without a list of tweets to length" unless tag.locals.tweets
136
+ tag.locals.tweets.length
137
+ end
138
+
139
+ desc %{
140
+ Usage:
141
+
142
+ This is a shortcut that displays messages from a twitter user's timeline.
143
+ The username can be specified with a 'user' parameter, or we will default to the Radiant.configured twitter user.
144
+ The number of messages is determined by the 'max' parameter, which must be 10 or less. Default is 5.
145
+
146
+ <pre><code><r:twitter:messages max="10" /></code></pre>
147
+ }
148
+ tag 'twitter:messages' do |tag|
149
+ out = ""
150
+ tag.locals.tweets ||= fetch_and_cache_tweets(:user => tag.attr['user'], :max => tag.attr['max'])
151
+ tag.locals.tweets.each do |tweet|
152
+ tag.locals.tweet = tweet
153
+ out << tag.render('tweet:message')
154
+ end
155
+ out
156
+ end
157
+
158
+ deprecated_tag 'twitter:message', :substitute => 'twitter:messages'
159
+
160
+ tag 'tweet' do |tag|
161
+ tag.expand if tag.locals.tweet
162
+ end
163
+
164
+ desc %{
165
+ Shortcut to display a single tweet in the standard way suggested by https://dev.twitter.com/terms/display-guidelines.
166
+
167
+ Note that for this to work you will probably want to include the twitter intents javascript in your page, and you may
168
+ also want to include the supplied `twitter.sass` in your site stylesheets.
169
+ }
170
+ tag 'tweet:message' do |tag|
171
+ if tweet = tag.locals.tweet
172
+ text = replace_links(tweet.text)
173
+ screen_name = tweet.from_user || tweet.user.screen_name # search returns a different data structure
174
+ date = tag.render('tweet:date', tag.attr.dup.merge('format' => "%d %B"))
175
+ %{
176
+ <p class="twitter">
177
+ <a class="twitter_avatar" href="http://twitter.com/#{screen_name}">#{tag.render("tweet:avatar")}</a>
178
+ <span class="tweet">
179
+ <a class="twitter_user" href="http://twitter.com/#{screen_name}">#{screen_name}</a>
180
+ <span class="twitter_name">#{tag.render('tweet:user:name')}</span>
181
+ <span class="twitter_text">#{text}</span>
182
+ <span class="twitter_links">
183
+ #{tag.render('tweet:permalink')}
184
+ #{tag.render('tweet:reply_link')}
185
+ #{tag.render('tweet:retweet_link')}
186
+ #{tag.render('tweet:favorite_link')}
187
+ </span>
188
+ </span>
189
+ </p>
190
+ }
191
+ end
192
+ end
193
+
194
+ [:coordinates, :in_reply_to_screen_name, :truncated, :in_reply_to_user_id, :in_reply_to_status_id,
195
+ :source, :place, :geo, :favorited, :contributors, :id].each do |method|
196
+ desc %{
197
+ Renders the @#{method.to_s}@ attribute of the tweet
198
+ <pre><code><r:tweet:#{method.to_s}/></code></pre>
199
+ }
200
+ tag "tweet:#{method.to_s}" do |tag|
201
+ tag.locals.tweet.send(method) if tag.locals.tweet.respond_to? method
202
+ end
203
+
204
+ desc %{
205
+ expands if the property has a value
206
+ <pre><code><r:tweet:if_#{method.to_s}/></code></pre>
207
+ }
208
+ tag "tweet:if_#{method.to_s}" do |tag|
209
+ value = tag.locals.tweet.send(method) if tag.locals.tweet.respond_to? method
210
+ tag.expand if !value.nil? && !value.empty?
211
+ end
212
+
213
+ desc %{
214
+ expands if the property has no value
215
+ <pre><code><r:tweet:unless_#{method.to_s}/></code></pre>
216
+ }
217
+ tag "tweet:unless_#{method.to_s}" do |tag|
218
+ value = tag.locals.tweet.send(method) if tag.locals.tweet.respond_to? method
219
+ tag.expand if value.nil? || value.empty?
220
+ end
221
+ end
222
+
223
+ [:date, :created_at].each do |method|
224
+ desc %{
225
+ renders the created_at timestamp of the tweet
226
+ <pre><code><r:tweet:#{method.to_s} [format="%c"]/></code></pre>
227
+ }
228
+ tag "tweet:#{method.to_s}" do |tag|
229
+ format = tag.attr['format'] || "%c"
230
+ date = DateTime.parse(tag.locals.tweet.created_at)
231
+ I18n.l date, :format => format
232
+ end
233
+ end
234
+
235
+ tag 'tweet:user' do |tag|
236
+ unless tag.locals.twitterer = tag.locals.tweet.user
237
+ tag.locals.twitterer = fetch_twitter_user(tag.locals.tweet.from_user)
238
+ end
239
+ raise TagError, "twitter user could not be found" unless tag.locals.twitterer
240
+ tag.expand
241
+ end
242
+
243
+ [:time_zone, :description, :lang, :profile_link_color, :profile_background_image_url, :profile_sidebar_fill_color, :following,
244
+ :profile_background_tile, :created_at, :statuses_count,:profile_sidebar_border_color,:profile_use_background_image,:followers_count,
245
+ :contributors_enabled,:notifications,:friends_count,:protected,:url,:profile_image_url,:geo_enabled,:profile_background_color,
246
+ :name,:favourites_count,:location,:screen_name, :id,:verified,:utc_offset,:profile_text_color].each do |method|
247
+ desc %{
248
+ Renders the @#{method.to_s}@ attribute of the tweeting user
249
+ <pre><code><r:tweet:user:#{method.to_s}/></code></pre>
250
+ }
251
+ tag "tweet:user:#{method.to_s}" do |tag|
252
+ tag.locals.twitterer.send(method)
253
+ end
254
+
255
+ desc %{
256
+ expands if @#{method.to_s}@ attribute of the tweeting user has a value
257
+ <pre><code><r:tweet:user:if_#{method.to_s}/></code></pre>
258
+ }
259
+ tag "tweet:user:if_#{method.to_s}" do |tag|
260
+ value = tag.locals.twitterer.send(method) rescue nil
261
+ tag.expand unless value.nil? || value.empty?
262
+ end
263
+
264
+ desc %{
265
+ expands if @#{method.to_s}@ attribute of the tweeting user has no value
266
+ <pre><code><r:tweet:user:unless_#{method.to_s}/></code></pre>
267
+ }
268
+ tag "tweet:user:unless_#{method.to_s}" do |tag|
269
+ value = tag.locals.twitterer.send(method) rescue nil
270
+ tag.expand if value.nil? || value.empty?
271
+ end
272
+ end
273
+
274
+ desc %{
275
+ Renders an avatar image for the tweeter of the current tweet.
276
+ }
277
+ tag 'tweet:avatar' do |tag|
278
+ url = tag.locals.tweet.profile_image_url || tag.render('tweet:user:profile_image_url')
279
+ %{<img src="#{url}" class="twitter_avatar" />}
280
+ end
281
+
282
+ desc %{
283
+ Renders the text for the current tweet.
284
+ }
285
+ tag 'tweet:text' do |tag|
286
+ tweet = tag.locals.tweet
287
+ replace_links(tweet.text)
288
+ end
289
+
290
+ desc %{
291
+ Renders the created ago string for the tweet e.g. Created 7 days...
292
+ }
293
+ tag 'tweet:created_ago' do |tag|
294
+ tweet = tag.locals.tweet
295
+ time_ago_in_words tweet.created_at
296
+ end
297
+
298
+ desc %{
299
+ Renders a permalink to this tweet with its date as the default link text.
300
+ }
301
+ tag 'tweet:permalink' do |tag|
302
+ cssclass = tag.attr['class'] || 'twitter_permalink'
303
+ text = tag.double? ? tag.expand : I18n.l(tag.locals.tweet.created_at, :twitter)
304
+ %{<a class="#{cssclass}" href="http://twitter.com/#!/#{screen_name}/status/#{tweet.id_str}">#{text}</a>}
305
+ end
306
+
307
+ desc %{
308
+ Renders a 'Reply' link that can be left as it is or hooked up by the twitter javascript.
309
+ }
310
+ tag 'tweet:reply_link' do |tag|
311
+ cssclass = tag.attr['class'] || 'twitter_reply'
312
+ text = tag.double? ? tag.expand : I18n.t('twitter_extension.reply')
313
+ %{<a class="#{cssclass}" href="http://twitter.com/intent/tweet?in_reply_to=#{tag.locals.tweet.id_str}">#{text}</a>}
314
+ end
315
+
316
+ desc %{
317
+ Renders a 'Retweet' link that can be left as it is or hooked up by the twitter javascript.
318
+ }
319
+ tag 'tweet:retweet_link' do |tag|
320
+ cssclass = tag.attr['class'] || 'twitter_retweet'
321
+ text = tag.double? ? tag.expand : I18n.t('twitter_extension.retweet')
322
+ %{<a class="#{cssclass}" href="http://twitter.com/intent/retweet?tweet_id=#{tag.locals.tweet.id_str}">#{text}</a>}
323
+ end
324
+
325
+ desc %{
326
+ Renders a 'Favorite' link that can be left as it is or hooked up by the twitter javascript.
327
+ }
328
+ tag 'tweet:favorite_link' do |tag|
329
+ cssclass = tag.attr['class'] || 'twitter_favorite'
330
+ text = tag.double? ? tag.expand : I18n.t('twitter_extension.favorite')
331
+ %{<a class="#{cssclass}" href="http://twitter.com/intent/favorite?tweet_id=#{tag.locals.tweet.id_str}">#{text}</a>}
332
+ end
333
+
334
+ private
335
+
336
+ # Retained for compatibility
337
+ #
338
+ def twitter_status(max = 1)
339
+ max = 1 if (max > 10) or (max < 1)
340
+ fetch_and_cache_tweets(:max => max)
341
+ end
342
+
343
+ # General-purpose tweet-fetcher using Rails::Cache to provide a calm-enhancing gap between similar
344
+ # requests. Set Radiant.config['twitter.expires_in'] to change the gap from 5 minutes.
345
+ # Always returns an array of tweet hashes (mashes, really).
346
+ # :max, :user, :list and :search options are used to determine the call we make (and the cache key).
347
+ # :page and :per_page options are passed through to the search call but not the user or list calls.
348
+ # other options are passed through (to non-search calls) unchanged.
349
+ #
350
+ def fetch_and_cache_tweets(options = {})
351
+ max = options.delete(:max) || 10
352
+ user = options.delete(:username) || Radiant.config['twitter.username']
353
+ list = options.delete(:list) || Radiant.config['twitter.listname']
354
+ search = options.delete(:search)
355
+ options[:count] ||= max
356
+ cache_key = ['twitter', list, user, max, search].compact.join('_')
357
+ begin
358
+ tweets = Rails.cache.fetch(cache_key,:expires_in => twitter_cache_duration) do
359
+ if search
360
+ Twitter::Search.new.containing(search).page(options[:page] || 1).per_page(options[:per_page] || 10).fetch
361
+ elsif list
362
+ twitter_client.list_timeline(user, list, options)
363
+ else
364
+ twitter_client.user_timeline(user, options)
365
+ end
366
+ end
367
+
368
+ rescue Twitter::Error => e
369
+ logger.error "Unable to fetch timeline: #{e.inspect}"
370
+ end
371
+
372
+ tweets || []
373
+ end
374
+
375
+ def fetch_twitter_user(screen_name)
376
+ cache_key = "twitter_user_#{screen_name}"
377
+ begin
378
+ twitter_user = Rails.cache.fetch(cache_key,:expires_in => twitter_cache_duration) do
379
+ twitter_client.user(screen_name)
380
+ end
381
+ rescue Twitter::Error => e
382
+ logger.error "Unable to fetch user '#{screen_name}': #{e.inspect}"
383
+ end
384
+ end
385
+
386
+ # these operations don't require authentication
387
+ #
388
+ def twitter_client
389
+ @twitter_client ||= Twitter::Client.new
390
+ end
391
+
392
+ # Turns http
393
+ #
394
+ def replace_links(text)
395
+ text = text.gsub(/(https?:\/\/\S*)/, '<a class="twitter_link" href="\1">\1</a>')
396
+ text = text.gsub(/@(\w*)/, '@<a class="twitter_link" href="http://twitter.com/\1">\1</a>')
397
+ text = text.gsub(/#(\w*)/, '<a class="twitter_link" href="http://twitter.com/search/#\1">#\1</a>')
398
+ end
399
+
400
+ # The interval between twitter api calls with the same parameters is set by the
401
+ # `twitter.expires_in` config entry and defaults to 5 minutes.
402
+ #
403
+ def twitter_cache_duration
404
+ @twitter_expires_in ||= (Radiant::Config["twitter.expires_in"] || 5).to_i.minutes
405
+ end
406
+ end
Binary file
Binary file
@@ -0,0 +1,46 @@
1
+ p.twitter
2
+ a.twitter_avatar
3
+ float: left
4
+ margin-right: 0.8em
5
+ img
6
+ margin-top: 0.8em
7
+ span.tweet
8
+ display: block
9
+ overflow: hidden
10
+ a.twitter_user
11
+ font-size: 150%
12
+ font-weight: normal
13
+ span.twitter_name
14
+ color: #b2b2b2
15
+ span.twitter_text
16
+ display: block
17
+ span.twitter_links
18
+ display: block
19
+ font-size: 80%
20
+ a
21
+ padding-left: 18px
22
+ height: 16px
23
+ color: #b2b2b2
24
+ background:
25
+ position: top left
26
+ repeat: no-repeat
27
+ image: url(/images/twitter/sprite.png)
28
+ &:hover
29
+ color: #666666
30
+ a.twitter_permalink
31
+ a.twitter_reply
32
+ background-position: 0 -16px
33
+ &:hover
34
+ background-position: 0 -32px
35
+ a.twitter_favourite
36
+ background-position: 0 -48px
37
+ &:hover
38
+ background-position: 0 -64px
39
+ a.twitter_retweet
40
+ background-position: 0 -96px
41
+ &:hover
42
+ background-position: 0 -112px
43
+ a.twitter_favorite
44
+ background-position: 0 -80px
45
+ &:hover
46
+ background-position: 0 -112px
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "radiant-twitter-extension"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "radiant-twitter-extension"
7
+ s.version = RadiantTwitterExtension::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = RadiantTwitterExtension::AUTHORS
10
+ s.email = RadiantTwitterExtension::EMAIL
11
+ s.homepage = RadiantTwitterExtension::URL
12
+ s.summary = RadiantTwitterExtension::SUMMARY
13
+ s.description = RadiantTwitterExtension::DESCRIPTION
14
+
15
+ s.add_dependency 'twitter', "~> 1.6.0"
16
+
17
+ ignores = if File.exist?('.gitignore')
18
+ File.read('.gitignore').split("\n").inject([]) {|a,p| a + Dir[p] }
19
+ else
20
+ []
21
+ end
22
+ s.files = Dir['**/*'] - ignores
23
+ s.test_files = Dir['test/**/*','spec/**/*','features/**/*'] - ignores
24
+ # s.executables = Dir['bin/*'] - ignores
25
+ s.require_paths = ["lib"]
26
+
27
+ s.post_install_message = %{
28
+ Add this to your radiant project with:
29
+ config.gem 'radiant-twitter-extension', :version => '~>#{RadiantTwitterExtension::VERSION}'
30
+ }
31
+ end
@@ -0,0 +1,114 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe 'TwitterTags' do
4
+ dataset :pages
5
+
6
+ before do
7
+ Radiant.config['twitter.username'] = 'testy'
8
+ Radiant.config['twitter.password'] = 'secret'
9
+
10
+ @client = mock("HTTPAuth (client)").as_null_object
11
+
12
+ # I've been getting odd failures with mock tweets
13
+ # when they're passed into a radius context
14
+
15
+ @tweets = (1..10).collect do |i|
16
+ OpenStruct.new.tap do |tweet|
17
+ tweet.text = "tweet #{i}"
18
+ tweet.created_at = DateTime.new(2010, 2, i+1).to_s
19
+ tweet.source = "<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>"
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '<r:twitter> The main context' do
25
+ it 'should give no output' do
26
+ tag = %{<r:twitter />}
27
+ pages(:home).should render(tag).as('')
28
+ end
29
+ end
30
+
31
+ describe '<r:twitter:tweets> Collect the users recent tweets' do
32
+ before(:each) do
33
+ Twitter::Client.stub!(:new).and_return(@client)
34
+ @client.stub!(:user_timeline).and_return(@tweets)
35
+ end
36
+
37
+ it 'should give no output' do
38
+ tag = %{<r:twitter><r:tweets></r:tweets></r:twitter>}
39
+ pages(:home).should render(tag).as('')
40
+ end
41
+
42
+ it 'should report the correct number of tweets' do
43
+ tag = %{<r:twitter><r:tweets:length /></r:twitter>}
44
+ pages(:home).should render(tag).as("10")
45
+ end
46
+
47
+ it 'should return the tweet text and replace links' do
48
+ tag = %{<r:twitter><r:tweets:each><r:tweet:text /></r:tweets:each></r:twitter>}
49
+ expected = @tweets.map(&:text).join('')
50
+ pages(:home).should render(tag).as(expected)
51
+ end
52
+
53
+ it 'should return the created at timestamp' do
54
+ tag = %{<r:twitter><r:tweets:each><r:tweet:created_at format="%d %B" /></r:tweets:each></r:twitter>}
55
+ expected = (1..10).map{|i| "#{'%02d' % (i+1)} February"}.join('')
56
+ pages(:home).should render(tag).as(expected)
57
+ end
58
+
59
+ it 'should return the created ago string' do
60
+ tag = %{<r:twitter><r:tweets:each><r:tweet:created_ago /></r:tweets:each></r:twitter>}
61
+ Time.stub!(:now).and_return(Time.parse("Feb 12 2010"))
62
+ expected = '10 days9 days8 days7 days6 days5 days4 days3 days2 days1 day'
63
+ pages(:home).should render(tag).as(expected)
64
+ end
65
+
66
+ it 'should return the source' do
67
+ tag = %{<r:twitter><r:tweets:each><r:tweet:source /></r:tweets:each></r:twitter>}
68
+ expected = @tweets.map(&:source).join('')
69
+ pages(:home).should render(tag).as(expected)
70
+ end
71
+ end
72
+
73
+ describe '<r:twitter:list list="list"> Collect the users list tweets' do
74
+ before(:each) do
75
+ Twitter::Client.stub!(:new).and_return(@client)
76
+ @client.stub!(:list_timeline).and_return(@tweets)
77
+ end
78
+
79
+ it 'should give no output' do
80
+ tag = %{<r:twitter><r:list list="list"></r:list></r:twitter>}
81
+ pages(:home).should render(tag).as('')
82
+ end
83
+
84
+ it 'should report the correct number of tweets (default 10)' do
85
+ tag = %{<r:twitter><r:list list="list"><r:length /></r:list></r:twitter>}
86
+ pages(:home).should render(tag).as("10")
87
+ end
88
+
89
+ it 'should return the tweet text and replace links' do
90
+ tag = %{<r:twitter><r:list list="list"><r:each><r:tweet:text /></r:each></r:list></r:twitter>}
91
+ expected = @tweets.map(&:text).join('')
92
+ pages(:home).should render(tag).as(expected)
93
+ end
94
+
95
+ it 'should return the created at timestamp' do
96
+ tag = %{<r:twitter><r:list list="list"><r:each><r:tweet:created_at format="%d %B" /></r:each></r:list></r:twitter>}
97
+ expected = (1..10).map{|i| "#{'%02d' % (i+1)} February"}.join('')
98
+ pages(:home).should render(tag).as(expected)
99
+ end
100
+
101
+ it 'should return the created ago string' do
102
+ tag = %{<r:twitter><r:list list="list"><r:each><r:tweet:created_ago /></r:each></r:list></r:twitter>}
103
+ Time.stub!(:now).and_return(Time.parse("Feb 12 2010"))
104
+ expected = '10 days9 days8 days7 days6 days5 days4 days3 days2 days1 day'
105
+ pages(:home).should render(tag).as(expected)
106
+ end
107
+
108
+ it 'should return the source' do
109
+ tag = %{<r:twitter><r:list list="list"><r:each><r:tweet:source /></r:each></r:list></r:twitter>}
110
+ expected = @tweets.map(&:source).join('')
111
+ pages(:home).should render(tag).as(expected)
112
+ end
113
+ end
114
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ unless defined? RADIANT_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["RADIANT_ENV_FILE"]
5
+ require ENV["RADIANT_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{RADIANT_ROOT}/spec/spec_helper"
13
+
14
+ if File.directory?(File.dirname(__FILE__) + "/scenarios")
15
+ Scenario.load_paths.unshift File.dirname(__FILE__) + "/scenarios"
16
+ end
17
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
18
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
19
+ end
20
+
21
+ Spec::Runner.configure do |config|
22
+ # config.use_transactional_fixtures = true
23
+ # config.use_instantiated_fixtures = false
24
+ config.fixture_path = File.dirname(__FILE__) + '/spec/fixtures'
25
+
26
+ # You can declare fixtures for each behaviour like this:
27
+ # describe "...." do
28
+ # fixtures :table_a, :table_b
29
+ #
30
+ # Alternatively, if you prefer to declare them only once, you can
31
+ # do so here, like so ...
32
+ #
33
+ # config.global_fixtures = :table_a, :table_b
34
+ #
35
+ # If you declare global fixtures, be aware that they will be declared
36
+ # for all of your examples, even those that don't use them.
37
+ end
@@ -0,0 +1,18 @@
1
+ class TwitterExtension < Radiant::Extension
2
+ version RadiantTwitterExtension::VERSION
3
+ description RadiantTwitterExtension::DESCRIPTION
4
+ url RadiantTwitterExtension::URL
5
+
6
+ extension_config do |config|
7
+ config.gem "twitter", :version => "~> 1.6.0"
8
+ end
9
+
10
+ def activate
11
+ Page.send :include, TwitterNotification # tweet page title upon publication
12
+ Page.send :include, TwitterTags # radius tags to display twitter search results
13
+
14
+ admin.pages.edit.add :extended_metadata, "twitter" # toggle twitter-posting at parent level
15
+ admin.configuration.show.add :config, 'admin/configuration/twitter_show', :after => 'defaults'
16
+ admin.configuration.edit.add :form, 'admin/configuration/twitter_edit', :after => 'edit_defaults'
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
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,56 @@
1
+ Filestore Cache Expires_in Plugin
2
+ ============================
3
+
4
+ Adds a :expires_in option to Rails filestore caching, in line with memcached store. Providing a very easy way to add high capacity caching to a site.
5
+
6
+ Model observers and sweepers are still useable as well, of course.
7
+
8
+ Filestore caching is a much easier method of caching to implement quickly than memcached, since it just involves writing the cache data to files in the tmp/ directory (also making it good for shared hosting environments).
9
+
10
+ Installation
11
+ ------
12
+
13
+ 1) Install plugin
14
+
15
+ ./script/plugin install git://github.com/adamsalter/filestore_expires_in-plugin.git
16
+
17
+ 2) Enable :file_store caching
18
+
19
+ config/environments/production.rb:
20
+
21
+ config.action_controller.perform_caching = true
22
+ config.cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache"
23
+
24
+ Useage
25
+ ------
26
+
27
+ On controller classes:
28
+
29
+ class MyController < ApplicationController
30
+ caches_action :show, {:if => etc.}, {:expires_in => 1.day}
31
+ end
32
+
33
+ In controller methods:
34
+
35
+ unless read_fragment({:controller => 'mycontroller', etc.}, {:expires_in => 1.day})
36
+ #code here
37
+ end
38
+
39
+ In views:
40
+
41
+ cache({:controller => 'mycontroller', etc.}, {:expires_in => 1.day}) do
42
+ #fragment here
43
+ end
44
+
45
+ In models:
46
+
47
+ cache_key = "models/my_model/%s?%s-%s-%s" % ["model_method_name", self.value, page, limit]
48
+
49
+ result = Rails.cache.fetch(cache_key, :expires_in => 1.day) do
50
+ # result data to be cached
51
+ end
52
+
53
+
54
+ Copyright (c) 2009 Adam @ [Codebright.net][cb], released under the MIT license
55
+
56
+ [cb]:http://codebright.net
@@ -0,0 +1,3 @@
1
+ # Include hook code here
2
+
3
+ require 'active_support/cache/file_store_extras'
@@ -0,0 +1,26 @@
1
+
2
+ module ActiveSupport
3
+ module Cache
4
+ class FileStore < Store
5
+ def read(name, options = nil)
6
+ super
7
+ file_name = real_file_path(name)
8
+ expires = expires_in(options)
9
+
10
+ if exist_without_instrument?(file_name, expires)
11
+ File.open(file_name, 'rb') { |f| Marshal.load(f) }
12
+ end
13
+ end
14
+
15
+ def exist?(name, options = nil)
16
+ super
17
+ File.exist?(real_file_path(name))
18
+ exist_without_instrument?(real_file_path(name), expires_in(options))
19
+ end
20
+
21
+ def exist_without_instrument?(file_name, expires)
22
+ File.exist?(file_name) && (expires <= 0 || Time.now - File.mtime(file_name) < expires)
23
+ end
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-twitter-extension
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15424087
5
+ prerelease: 6
6
+ segments:
7
+ - 2
8
+ - 0
9
+ - 0
10
+ - rc
11
+ - 1
12
+ version: 2.0.0.rc1
13
+ platform: ruby
14
+ authors:
15
+ - Sean Cribbs
16
+ - Edmund Haselwanter
17
+ - Jim Gay
18
+ - William Ross
19
+ autorequire:
20
+ bindir: bin
21
+ cert_chain: []
22
+
23
+ date: 2011-07-28 00:00:00 +01:00
24
+ default_executable:
25
+ dependencies:
26
+ - !ruby/object:Gem::Dependency
27
+ name: twitter
28
+ prerelease: false
29
+ requirement: &id001 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ hash: 15
35
+ segments:
36
+ - 1
37
+ - 6
38
+ - 0
39
+ version: 1.6.0
40
+ type: :runtime
41
+ version_requirements: *id001
42
+ description: Posts notification of pages to Twitter and provides radiius tags to display the results of twitter searches.
43
+ email:
44
+ - radiant@radiantcms.org
45
+ executables: []
46
+
47
+ extensions: []
48
+
49
+ extra_rdoc_files: []
50
+
51
+ files:
52
+ - app/views/admin/configuration/_twitter_edit.html.haml
53
+ - app/views/admin/configuration/_twitter_show.html.haml
54
+ - app/views/admin/pages/_twitter.html.haml
55
+ - config/initializers/radiant_config.rb
56
+ - config/locales/en.yml
57
+ - db/migrate/001_add_twitter_notification_fields.rb
58
+ - HELP_admin.md
59
+ - lib/radiant-twitter-extension.rb
60
+ - lib/tasks/twitter_extension_tasks.rake
61
+ - lib/twitter_notification.rb
62
+ - lib/twitter_tags.rb
63
+ - public/images/twitter/bird.png
64
+ - public/images/twitter/sprite.png
65
+ - public/stylesheets/sass/twitter.sass
66
+ - radiant-twitter-extension.gemspec
67
+ - Rakefile
68
+ - README.md
69
+ - spec/lib/twitter_tags_spec.rb
70
+ - spec/spec.opts
71
+ - spec/spec_helper.rb
72
+ - twitter_extension.rb
73
+ - vendor/plugins/filestore_expires_in-plugin/init.rb
74
+ - vendor/plugins/filestore_expires_in-plugin/lib/active_support/cache/file_store_extras.rb
75
+ - vendor/plugins/filestore_expires_in-plugin/MIT-LICENSE
76
+ - vendor/plugins/filestore_expires_in-plugin/README.md
77
+ has_rdoc: true
78
+ homepage: http://github.com/ehaselwanter/radiant-twitter-extension
79
+ licenses: []
80
+
81
+ post_install_message: "\n Add this to your radiant project with:\n config.gem 'radiant-twitter-extension', :version => '~>2.0.0.rc1'\n "
82
+ rdoc_options: []
83
+
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">"
99
+ - !ruby/object:Gem::Version
100
+ hash: 25
101
+ segments:
102
+ - 1
103
+ - 3
104
+ - 1
105
+ version: 1.3.1
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.5.3
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Twitter posting and radius tags for twitter feeds.
113
+ test_files:
114
+ - spec/lib/twitter_tags_spec.rb
115
+ - spec/spec.opts
116
+ - spec/spec_helper.rb