cartoonist-twitter 0.0.9
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 +2 -0
- data/app/controllers/admin/tweets_controller.rb +38 -0
- data/app/models/tweet.rb +214 -0
- data/app/views/admin/tweets/_entity_tweet.html.erb +22 -0
- data/app/views/admin/tweets/edit.html.erb +5 -0
- data/app/views/admin/tweets/index.html.erb +21 -0
- data/app/views/layouts/admin/tweets.html.erb +3 -0
- data/cartoonist-twitter.gemspec +16 -0
- data/config/locales/en.yml +43 -0
- data/db/migrate/20120501083235_create_tweets.rb +14 -0
- data/lib/cartoonist-twitter/engine.rb +67 -0
- data/lib/cartoonist-twitter.rb +5 -0
- metadata +78 -0
data/.gitignore
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class Admin::TweetsController < CartoonistController
|
2
|
+
before_filter :ensure_ssl!
|
3
|
+
before_filter :check_admin!
|
4
|
+
|
5
|
+
def index
|
6
|
+
@untweeted = Tweet.untweeted.created_chronological.not_disabled
|
7
|
+
@tweeted = Tweet.tweeted.reverse_chronological
|
8
|
+
end
|
9
|
+
|
10
|
+
def edit
|
11
|
+
@tweet = Tweet.find params[:id].to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
@tweet = Tweet.update_tweet params
|
16
|
+
send_tweet_if_requested
|
17
|
+
tweet_or_entity_redirect
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
@tweet = Tweet.create_tweet params
|
22
|
+
send_tweet_if_requested
|
23
|
+
tweet_or_entity_redirect
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def send_tweet_if_requested
|
28
|
+
@tweet.manual_tweet! if params[:tweet_now].present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def tweet_or_entity_redirect
|
32
|
+
if params[:destination] == "entity_edit" && @tweet.entity.entity_edit_url
|
33
|
+
redirect_to @tweet.entity.entity_edit_url
|
34
|
+
else
|
35
|
+
redirect_to "/admin/tweets/#{@tweet.id}/edit"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/app/models/tweet.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
class Tweet < ActiveRecord::Base
|
2
|
+
validate :doesnt_update_tweet_after_tweeted
|
3
|
+
validate :entity_doesnt_change, :on => :update
|
4
|
+
attr_accessible :entity_id, :entity_type, :tweet, :tweeted_at
|
5
|
+
|
6
|
+
def allow_tweet_now?
|
7
|
+
if entity.kind_of? Postable
|
8
|
+
posted = entity.posted?
|
9
|
+
else
|
10
|
+
posted = true
|
11
|
+
end
|
12
|
+
|
13
|
+
allow_save? && !disabled? && posted
|
14
|
+
end
|
15
|
+
|
16
|
+
def allow_save?
|
17
|
+
!tweeted?
|
18
|
+
end
|
19
|
+
|
20
|
+
def disabled?
|
21
|
+
tweet_style == :disabled
|
22
|
+
end
|
23
|
+
|
24
|
+
def entity
|
25
|
+
@entity ||= Cartoonist::Entity[entity_type.to_sym].find(entity_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def description
|
29
|
+
"#{entity.entity_localized_label}: #{entity.entity_description}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def formatted_tweeted_at(default_msg = "not yet tweeted")
|
33
|
+
return default_msg unless tweeted_at
|
34
|
+
tweeted_at.localtime.strftime "%-m/%-d/%Y at %-l:%M %P"
|
35
|
+
end
|
36
|
+
|
37
|
+
def manual_tweet!
|
38
|
+
raise "Tweeting is not allowed!" unless allow_tweet_now?
|
39
|
+
return if tweeted?
|
40
|
+
return if disabled?
|
41
|
+
send_tweet!
|
42
|
+
end
|
43
|
+
|
44
|
+
def auto_tweet!
|
45
|
+
return if tweeted?
|
46
|
+
return unless expected_tweet_time
|
47
|
+
return unless Time.now >= expected_tweet_time
|
48
|
+
send_tweet!
|
49
|
+
end
|
50
|
+
|
51
|
+
def tweet_style
|
52
|
+
Setting[:"#{entity.entity_type}_tweet_style"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def tweet_time
|
56
|
+
Setting[:"#{entity.entity_type}_tweet_time"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def form_path
|
60
|
+
if new_record?
|
61
|
+
"/admin/tweets"
|
62
|
+
else
|
63
|
+
"/admin/tweets/#{id}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def form_method
|
68
|
+
if new_record?
|
69
|
+
:post
|
70
|
+
else
|
71
|
+
:put
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def expected_tweet_time
|
76
|
+
case tweet_style
|
77
|
+
when :disabled
|
78
|
+
nil
|
79
|
+
when :manual
|
80
|
+
nil
|
81
|
+
when :automatic
|
82
|
+
entity.posted_at
|
83
|
+
when :automatic_timed
|
84
|
+
if tweet_time.blank?
|
85
|
+
entity.posted_at
|
86
|
+
elsif entity.posted_at
|
87
|
+
parsed = DateTime.strptime("#{entity.posted_at.year}-#{entity.posted_at.month}-#{entity.posted_at.day} #{tweet_time.downcase}", "%Y-%m-%d %I:%M %p").to_time
|
88
|
+
result = Time.local entity.posted_at.year, entity.posted_at.month, entity.posted_at.day, parsed.hour, parsed.min
|
89
|
+
result = result + 1.day if result < entity.posted_at.to_time
|
90
|
+
result
|
91
|
+
end
|
92
|
+
else
|
93
|
+
raise "Invalid tweet style #{tweet_style}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def tweeted?
|
98
|
+
tweeted_at.present?
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def send_tweet!
|
103
|
+
if Rails.env.production?
|
104
|
+
Twitter.update tweet
|
105
|
+
else
|
106
|
+
logger.info "Fake Tweet: #{tweet}"
|
107
|
+
end
|
108
|
+
|
109
|
+
self.tweeted_at = Time.now
|
110
|
+
save!
|
111
|
+
end
|
112
|
+
|
113
|
+
def doesnt_update_tweet_after_tweeted
|
114
|
+
if !tweeted_at_was.nil? && tweet_changed?
|
115
|
+
errors.add :tweet, "can't change after the tweet has been sent"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def entity_doesnt_change
|
120
|
+
if entity_id_changed?
|
121
|
+
errors.add :entity_id, "can't change"
|
122
|
+
end
|
123
|
+
|
124
|
+
if entity_type_changed?
|
125
|
+
errors.add :entity_id, "can't change"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class << self
|
130
|
+
def update_tweet(params)
|
131
|
+
tweet = find params[:id].to_i
|
132
|
+
raise "Saving is not allowed!" unless tweet.allow_save?
|
133
|
+
tweet.tweet = params[:tweet]
|
134
|
+
tweet.save!
|
135
|
+
tweet
|
136
|
+
end
|
137
|
+
|
138
|
+
def create_tweet(params)
|
139
|
+
raise "The entity_id is required!" if params[:entity_id].blank?
|
140
|
+
raise "The entity_type is required!" if params[:entity_type].blank?
|
141
|
+
create :entity_id => params[:entity_id].to_i, :entity_type => params[:entity_type], :tweet => params[:tweet]
|
142
|
+
end
|
143
|
+
|
144
|
+
def tweet_for(entity)
|
145
|
+
result = find_for entity
|
146
|
+
|
147
|
+
if result
|
148
|
+
result
|
149
|
+
else
|
150
|
+
new options_for(entity)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_for(entity)
|
155
|
+
create options_for(entity)
|
156
|
+
end
|
157
|
+
|
158
|
+
def options_for(entity)
|
159
|
+
{ :entity_id => entity.id, :entity_type => entity.entity_type, :tweet => SimpleTemplate[Setting[:"#{entity.entity_type}_default_tweet"], :self => entity] }
|
160
|
+
end
|
161
|
+
|
162
|
+
def find_for(entity)
|
163
|
+
raise "Can only find tweets for entities!" unless entity.kind_of? Entity
|
164
|
+
where({ :entity_id => entity.id, :entity_type => entity.entity_type }).first
|
165
|
+
end
|
166
|
+
|
167
|
+
def tweeted
|
168
|
+
where "tweeted_at IS NOT NULL"
|
169
|
+
end
|
170
|
+
|
171
|
+
def untweeted
|
172
|
+
where "tweeted_at IS NULL"
|
173
|
+
end
|
174
|
+
|
175
|
+
def chronological
|
176
|
+
order "tweeted_at ASC"
|
177
|
+
end
|
178
|
+
|
179
|
+
def reverse_chronological
|
180
|
+
order "tweeted_at DESC"
|
181
|
+
end
|
182
|
+
|
183
|
+
def created_chronological
|
184
|
+
order "created_at ASC"
|
185
|
+
end
|
186
|
+
|
187
|
+
def created_reverse_chronological
|
188
|
+
order "created_at DESC"
|
189
|
+
end
|
190
|
+
|
191
|
+
def not_disabled
|
192
|
+
result = all
|
193
|
+
|
194
|
+
types = result.map(&:entity_type).uniq.select do |t|
|
195
|
+
Setting[:"#{t}_tweet_style"] != :disabled
|
196
|
+
end
|
197
|
+
|
198
|
+
result.select { |x| types.include? x.entity_type }
|
199
|
+
end
|
200
|
+
|
201
|
+
def styles(entity)
|
202
|
+
results = []
|
203
|
+
results << { :value => :disabled, :label => "tweet.style.disabled" }
|
204
|
+
results << { :value => :manual, :label => "tweet.style.manual" }
|
205
|
+
|
206
|
+
if Cartoonist::Entity[entity].include? Postable
|
207
|
+
results << { :value => :automatic, :label => "tweet.style.automatic" }
|
208
|
+
results << { :value => :automatic_timed, :label => "tweet.style.automatic_timed" }
|
209
|
+
end
|
210
|
+
|
211
|
+
results
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<% tweet = Tweet.tweet_for entity %>
|
2
|
+
<% if tweet.tweet_style != :disabled %>
|
3
|
+
<% destination = :entity_edit if destination.nil? %>
|
4
|
+
<%= form_tag tweet.form_path, :method => tweet.form_method do %>
|
5
|
+
<input type="hidden" name="entity_id" value="<%= tweet.entity_id %>" />
|
6
|
+
<input type="hidden" name="entity_type" value="<%= tweet.entity_type %>" />
|
7
|
+
<input type="hidden" name="destination" value="<%= destination %>" />
|
8
|
+
|
9
|
+
<p>
|
10
|
+
<%= t "admin.tweets.entity_tweet.tweet" %><br />
|
11
|
+
<textarea name="tweet" rows="2" cols="100" <%= 'disabled="disabled"'.html_safe unless tweet.allow_save? %>><%= tweet.tweet %></textarea>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<p>
|
15
|
+
<input type="submit" name="save" value="<%= t "admin.tweets.entity_tweet.save" %>" <%= 'disabled="disabled"'.html_safe unless tweet.allow_save? %> />
|
16
|
+
</p>
|
17
|
+
|
18
|
+
<p>
|
19
|
+
<input type="submit" name="tweet_now" value="<%= t "admin.tweets.entity_tweet.tweet_now" %>" <%= 'disabled="disabled"'.html_safe unless tweet.allow_tweet_now? %> />
|
20
|
+
</p>
|
21
|
+
<% end %>
|
22
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h2><%= t "admin.tweets.index.not_tweeted" %></h2>
|
2
|
+
|
3
|
+
<ul>
|
4
|
+
<% @untweeted.each do |tweet| %>
|
5
|
+
<li>
|
6
|
+
<%= tweet.formatted_tweeted_at "" %>
|
7
|
+
<a href="/admin/tweets/<%= tweet.id %>/edit"><%= tweet.description %></a>
|
8
|
+
</li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
11
|
+
|
12
|
+
<h2><%= t "admin.tweets.index.tweeted" %></h2>
|
13
|
+
|
14
|
+
<ul>
|
15
|
+
<% @tweeted.each do |tweet| %>
|
16
|
+
<li>
|
17
|
+
<%= tweet.formatted_tweeted_at "" %>
|
18
|
+
<a href="/admin/tweets/<%= tweet.id %>/edit"><%= tweet.description %></a>
|
19
|
+
</li>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
raise "Cannot find version file!" unless File.exists?(File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION"))
|
3
|
+
cartoonist_version = File.read(File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION")).strip
|
4
|
+
s.name = "cartoonist-twitter"
|
5
|
+
s.version = cartoonist_version
|
6
|
+
s.date = Time.now.strftime "%Y-%m-%d"
|
7
|
+
s.summary = "Cartoonist Twitter"
|
8
|
+
s.description = "Plugin to allow tweeting of cartoonist entities."
|
9
|
+
s.authors = ["Mike Virata-Stone"]
|
10
|
+
s.email = "reasonnumber@gmail.com"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.homepage = "http://reasonnumber.com/cartoonist"
|
14
|
+
s.add_dependency "cartoonist", cartoonist_version
|
15
|
+
s.add_dependency "twitter", "~> 2.2.0"
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
en:
|
2
|
+
admin:
|
3
|
+
layout:
|
4
|
+
tab:
|
5
|
+
tweets: Tweets
|
6
|
+
tweets:
|
7
|
+
entity_tweet:
|
8
|
+
save: Save
|
9
|
+
tweet: "Tweet:"
|
10
|
+
tweet_now: Tweet Now
|
11
|
+
index:
|
12
|
+
not_tweeted: Not yet tweeted
|
13
|
+
tweeted: Tweeted
|
14
|
+
layout:
|
15
|
+
section: Tweets
|
16
|
+
cartoonist:
|
17
|
+
layout:
|
18
|
+
navigation:
|
19
|
+
follow_on_twitter: Follow us on Twitter
|
20
|
+
follow_on_twitter_title: Follow us on Twitter
|
21
|
+
settings:
|
22
|
+
show:
|
23
|
+
errors:
|
24
|
+
invalid_tweet_time: "Invalid tweet time '%{value}' should be formatted like: '1:22 pm' or '11:30 am'"
|
25
|
+
sections:
|
26
|
+
social_and_analytics:
|
27
|
+
twitter: Twitter
|
28
|
+
settings:
|
29
|
+
default_tweet: "%{entity} Default Tweet: "
|
30
|
+
tweet_style: "%{entity} Tweet Style: "
|
31
|
+
tweet_time: "%{entity} Tweet Time: "
|
32
|
+
tweet_time_info: "Time to tweet when style is \"Automatic at a specific time\" (format example: 3:30 pm)"
|
33
|
+
twitter_consumer_key: "Twitter Consumer Key: "
|
34
|
+
twitter_consumer_secret: "Twitter Consumer Secret: "
|
35
|
+
twitter_handle: "Twitter Handle: "
|
36
|
+
twitter_oauth_token: "Twitter Oauth Token: "
|
37
|
+
twitter_oauth_token_secret: "Twitter Oauth Token Secret: "
|
38
|
+
tweet:
|
39
|
+
style:
|
40
|
+
automatic: Automatic after posted
|
41
|
+
automatic_timed: Automatic at a specific time
|
42
|
+
disabled: Disabled
|
43
|
+
manual: Manual only
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateTweets < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :tweets do |t|
|
4
|
+
t.integer :entity_id, :null => false
|
5
|
+
t.string :entity_type, :null => false
|
6
|
+
t.string :tweet, :null => false, :length => 140
|
7
|
+
t.datetime :tweeted_at
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :tweets, :tweeted_at
|
12
|
+
add_index :tweets, [:entity_id, :entity_type], :unique => true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module CartoonistTwitter
|
2
|
+
class EntityHooks
|
3
|
+
class << self
|
4
|
+
def after_entity_save(entity)
|
5
|
+
return if Setting[:"#{entity.entity_type}_tweet_style"] == :disabled
|
6
|
+
result = Tweet.find_for entity
|
7
|
+
Tweet.create_for entity unless result
|
8
|
+
end
|
9
|
+
|
10
|
+
def edit_entity_before_partial
|
11
|
+
"admin/tweets/entity_tweet"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Engine < ::Rails::Engine
|
17
|
+
config.to_prepare do
|
18
|
+
twitter_auth_changed = lambda do
|
19
|
+
Twitter.configure do |twitter_config|
|
20
|
+
twitter_config.consumer_key = Setting[:twitter_consumer_key]
|
21
|
+
twitter_config.consumer_secret = Setting[:twitter_consumer_secret]
|
22
|
+
twitter_config.oauth_token = Setting[:twitter_oauth_token]
|
23
|
+
twitter_config.oauth_token_secret = Setting[:twitter_oauth_token_secret]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Setting::Section.define :twitter, :order => 2, :tab => :social_and_analytics do
|
28
|
+
order = 0
|
29
|
+
|
30
|
+
Cartoonist::Entity.all.each do |entity|
|
31
|
+
Setting.define :"#{entity.entity_type}_tweet_style", :type => :symbol, :order => (order += 1), :label => lambda { I18n.t("settings.show.settings.tweet_style", :entity => entity.entity_localized_label) }, :select_from => lambda { Tweet.styles(entity.entity_type) }, :default => :disabled
|
32
|
+
Setting.define :"#{entity.entity_type}_tweet_time", :order => (order += 1), :label => lambda { I18n.t("settings.show.settings.tweet_time", :entity => entity.entity_localized_label) }, :info_label => "settings.show.settings.tweet_time_info", :validation => lambda { |value| raise Setting::InvalidError.new I18n.t("settings.show.errors.invalid_tweet_time", :value => value) unless value =~ /^((1[0-2]|[1-9])\:[0-5]\d (am|pm|AM|PM))?$/ }
|
33
|
+
Setting.define :"#{entity.entity_type}_default_tweet", :order => (order += 1), :label => lambda { I18n.t("settings.show.settings.default_tweet", :entity => entity.entity_localized_label) }
|
34
|
+
end
|
35
|
+
|
36
|
+
Setting.define :twitter_handle, :order => (order += 1)
|
37
|
+
Setting.define :twitter_consumer_key, :onchange => twitter_auth_changed, :order => (order += 1)
|
38
|
+
Setting.define :twitter_consumer_secret, :onchange => twitter_auth_changed, :order => (order += 1)
|
39
|
+
Setting.define :twitter_oauth_token, :onchange => twitter_auth_changed, :order => (order += 1)
|
40
|
+
Setting.define :twitter_oauth_token_secret, :onchange => twitter_auth_changed, :order => (order += 1)
|
41
|
+
end
|
42
|
+
|
43
|
+
twitter_auth_changed.call
|
44
|
+
end
|
45
|
+
|
46
|
+
Cartoonist::Admin::Tab.add :tweets, :url => "/admin/tweets"
|
47
|
+
Cartoonist::Navigation::Link.add :url => (lambda { "https://twitter.com/#{Setting[:twitter_handle]}" }), :class => "follow-us", :label => "cartoonist.layout.navigation.follow_on_twitter", :title => "cartoonist.layout.navigation.follow_on_twitter_title", :order => 2
|
48
|
+
Cartoonist::Migration.add_for self
|
49
|
+
Cartoonist::Entity.register_hooks CartoonistTwitter::EntityHooks
|
50
|
+
|
51
|
+
Cartoonist::Backup.for :tweets do
|
52
|
+
Tweet.order(:id).all
|
53
|
+
end
|
54
|
+
|
55
|
+
Cartoonist::Cron.add do
|
56
|
+
Tweet.untweeted.each do |tweet|
|
57
|
+
tweet.auto_tweet!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Cartoonist::Routes.add do
|
62
|
+
namespace :admin do
|
63
|
+
resources :tweets
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cartoonist-twitter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.9
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Virata-Stone
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cartoonist
|
16
|
+
requirement: &17879120 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - =
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.0.9
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *17879120
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: twitter
|
27
|
+
requirement: &17878040 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.2.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *17878040
|
36
|
+
description: Plugin to allow tweeting of cartoonist entities.
|
37
|
+
email: reasonnumber@gmail.com
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- .gitignore
|
43
|
+
- app/controllers/admin/tweets_controller.rb
|
44
|
+
- app/models/tweet.rb
|
45
|
+
- app/views/admin/tweets/_entity_tweet.html.erb
|
46
|
+
- app/views/admin/tweets/edit.html.erb
|
47
|
+
- app/views/admin/tweets/index.html.erb
|
48
|
+
- app/views/layouts/admin/tweets.html.erb
|
49
|
+
- cartoonist-twitter.gemspec
|
50
|
+
- config/locales/en.yml
|
51
|
+
- db/migrate/20120501083235_create_tweets.rb
|
52
|
+
- lib/cartoonist-twitter.rb
|
53
|
+
- lib/cartoonist-twitter/engine.rb
|
54
|
+
homepage: http://reasonnumber.com/cartoonist
|
55
|
+
licenses: []
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.8.17
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Cartoonist Twitter
|
78
|
+
test_files: []
|