cackle 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +32 -0
- data/lib/app/helpers/cackle_helper.rb +18 -0
- data/lib/app/models/cackle_comment.rb +5 -0
- data/lib/app/views/cackle/comments.html.haml +27 -0
- data/lib/app/views/cackle/recent.html.haml +62 -0
- data/lib/cackle.rb +13 -0
- data/lib/cackle/railtie.rb +7 -0
- data/lib/cackle/version.rb +3 -0
- data/lib/generators/cackle_migration/cackle_migration_generator.rb +19 -0
- data/lib/generators/cackle_migration/templates/migration.rb +22 -0
- data/lib/tasks/cackle_tasks.rake +90 -0
- data/test/cackle_test.rb +7 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +5 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/test_helper.rb +15 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 795976ed8d1dad277d90976a5b9c3b50043b847b
|
4
|
+
data.tar.gz: 73aeafd4731b674daa22a5645b2251c0cbbadfca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f1e8f3470be58a6abc29fc528c6aa767357c3846e4a520d7e417e60f76fc2ffb1c2c201ee950bab56a11fa917edf27864620427d9632b7f372dd4ed6d36381d
|
7
|
+
data.tar.gz: 66fe2a831c2b9f0340f736a3428c77b0e05d4c9e8674cad1174fe80d367a5b6055ccfc7cd435fe1f4267826c18109ca3a097eb0819e206491b2e641ee74e69a1
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
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.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
Cackle.me integration
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Simple Rails plugin implements synchronization of Cackle.me comments.
|
5
|
+
|
6
|
+
Cackle.me is a real-time comment system with the ability to login
|
7
|
+
via popular social networks such as Google+, Facebook, Twitter,
|
8
|
+
LinkedIn, Vkontakte, Odnoklassniki, Mail.ru and many others.
|
9
|
+
|
10
|
+
Storing in local database make comments visible to search robots.
|
11
|
+
|
12
|
+
Installation
|
13
|
+
------------
|
14
|
+
|
15
|
+
Add to Gemfile
|
16
|
+
```ruby
|
17
|
+
gem 'cackle'
|
18
|
+
```
|
19
|
+
|
20
|
+
Generate and run migration
|
21
|
+
```
|
22
|
+
rails g cacke_migration
|
23
|
+
rake db:migrate
|
24
|
+
```
|
25
|
+
Create config file config/cackle.yml
|
26
|
+
See http://cackle.me/help/comment-sync to get your keys
|
27
|
+
|
28
|
+
```yml
|
29
|
+
site_id: 12345 # Site ID
|
30
|
+
site_api_key: blah-blah-blah # Account API Key
|
31
|
+
account_api_key: blah-blah-blah # Site API Key
|
32
|
+
jquery_off: true # Disable including jQuery if you already have it loaded
|
33
|
+
|
34
|
+
recent: # configuretion for recent comments block
|
35
|
+
mcSize: 10 # how many comments to display
|
36
|
+
mcAvatarSize: 32 # size of avatar image in pixels
|
37
|
+
mcTextSize: 150 # length of message block if more shorten with '...'
|
38
|
+
mcTitleSize: 40 # title length
|
39
|
+
```
|
40
|
+
|
41
|
+
Helper methods
|
42
|
+
==============
|
43
|
+
|
44
|
+
Insert comments widget
|
45
|
+
```ruby
|
46
|
+
cackle_comments
|
47
|
+
```
|
48
|
+
Recent comments widget
|
49
|
+
```ruby
|
50
|
+
cackle_recent_comments
|
51
|
+
```
|
52
|
+
|
53
|
+
Rake tasks
|
54
|
+
==========
|
55
|
+
First time import. Warning clears all comments in base.
|
56
|
+
```
|
57
|
+
cackle:import
|
58
|
+
```
|
59
|
+
|
60
|
+
Syncronize changes. Should be called every 5 minutes by cron.
|
61
|
+
```
|
62
|
+
cackle:sync
|
63
|
+
```
|
64
|
+
|
65
|
+
License
|
66
|
+
-------
|
67
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Cackle'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CackleHelper
|
2
|
+
def cackle_comments
|
3
|
+
load_config
|
4
|
+
@comments = CackleComment.approved.where("url LIKE ?", "%#{request.path}")
|
5
|
+
render template: 'cackle/comments'
|
6
|
+
end
|
7
|
+
|
8
|
+
def cackle_recent_comments
|
9
|
+
load_config
|
10
|
+
@comments = CackleComment.approved.limit(@config['recent']['mcSize'])
|
11
|
+
render template: 'cackle/recent'
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def load_config
|
16
|
+
@config ||= YAML::load(File.open('config/cackle.yml'))
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#mc-container
|
2
|
+
#mc-content
|
3
|
+
%ul#cackle-comments
|
4
|
+
- @comments.each do |comment|
|
5
|
+
%li{ id: "cackle-comment-#{comment.comment_id}" }
|
6
|
+
#cackle-comment-header.cackle-comment-header
|
7
|
+
%cite{ id: "cackle-cite-#{comment.comment_id}" }
|
8
|
+
-if comment.author_name
|
9
|
+
= link_to comment.author_name, '#', target: '_blank', id: comment.comment_id, rel: 'nofollow'
|
10
|
+
-else
|
11
|
+
%span{ id: "cackle-author-user-#{comment.comment_id}" }= comment.author_name
|
12
|
+
.cackle-comment-body{ id: "cackle-comment-body-#{comment.comment_id}" }
|
13
|
+
.cackle-comment-message{ id: "cackle-comment-message-#{comment.comment_id}" }= comment.message
|
14
|
+
|
15
|
+
:javascript
|
16
|
+
var href = window.location.href;
|
17
|
+
if (href.indexOf('?') > 0) {
|
18
|
+
var mcChannel = href.substring(0, href.indexOf('?'));
|
19
|
+
};
|
20
|
+
var mcSite = '#{@config['site_id']}';
|
21
|
+
(function() {
|
22
|
+
var mc = document.createElement('script');
|
23
|
+
mc.type = 'text/javascript';
|
24
|
+
mc.async = true;
|
25
|
+
mc.src = 'http://cackle.me/mc.widget-min.js';
|
26
|
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(mc);
|
27
|
+
})();
|
@@ -0,0 +1,62 @@
|
|
1
|
+
:css
|
2
|
+
.mc-last-content{position:relative!important;width:100%!important;display:inline-block!important}
|
3
|
+
.mc-last-content div,.mc-last-content p,.mc-last-content h3{display:block!important}
|
4
|
+
.mc-last-content ul,.mc-last-content li,.mc-last-content ol,.mc-last-content div,.mc-last-content p,.mc-last-content a,.mc-last-content img{background:none repeat scroll 0 50% transparent!important;border:0 none!important;font-style:normal!important;margin:0!important;padding:0!important;text-align:left!important;text-indent:0!important}
|
5
|
+
.mc-last-content ul,.mc-last-content li{border:none!important;list-style:none!important;list-style-position:outside!important;list-style-type:none!important;line-height:normal!important}
|
6
|
+
.mc-last-content li>div{margin-bottom:5px!important;position:relative!important;word-wrap:break-word!important}
|
7
|
+
.mc-last-content li .mc-recent-thumb{position:relative!important;margin-right:6px!important;padding:0!important;float:left!important;width:auto!important}
|
8
|
+
.mc-last-content li .mc-recent-thumb:after{border-radius:2px!important;box-shadow:0 0 3px rgba(0,0,0,0.33) inset!important;position:absolute!important;left:0!important;top:0!important;content:" "!important;width:100%!important;height:100%!important}
|
9
|
+
.mc-last-content .mc-recent-thumb img{border-radius:2px!important;max-width:100%!important;height:auto!important;float:left!important;vertical-align:middle!important;border:0!important}
|
10
|
+
.mc-last-content .mc-recent-body{margin-left:38px!important;line-height:15px!important}
|
11
|
+
.mc-last-content .mc-recent-author{color:#8a8a8a!important;font-size:13px!important;font-weight:bold!important;line-height:14px!important;text-decoration:none!important;padding:0!important}
|
12
|
+
.mc-last-content .mc-recent-text{font-size:12px!important;line-height:16px!important;margin-top:2px!important}
|
13
|
+
.mc-last-content .mc-recent-text a,.mc-last-content .mc-recent-text a:hover{color:inherit!important;text-decoration:none!important}
|
14
|
+
.mc-last-content .mc-recent-meta{border-bottom:1px dotted #e0e0e0!important;font-size:11px!important;line-height:15px!important;margin-top:4px!important;color:#a7a7a7!important}
|
15
|
+
.mc-last-content .mc-recent-meta a{text-decoration:none!important;color:#a7a7a7!important;font-size:11px!important}
|
16
|
+
#mc-link{color:#555!important;font-size:11px!important;clear:both!important;float:right;text-decoration:none!important}
|
17
|
+
#mc-link:hover{color:#333!important}
|
18
|
+
.mc-recent-thumb img{
|
19
|
+
width: #{@config['recent']['mcAvatarSize']}px;
|
20
|
+
height: #{@config['recent']['mcAvatarSize']}px;
|
21
|
+
}
|
22
|
+
#mc-last
|
23
|
+
.mc-last-content
|
24
|
+
%ul
|
25
|
+
- @comments.each do |comment|
|
26
|
+
%li
|
27
|
+
%div
|
28
|
+
- if comment.author_name
|
29
|
+
= link_to comment.author_www, target: '_blank' do
|
30
|
+
%span.mc-recent-thumb= image_tag(comment.author_avatar, alt: comment.author_name)
|
31
|
+
- else
|
32
|
+
%span.mc-recent-thumb= image_tag('http://cackle.me/static/img/anonym.png', alt: comment.anonym_name)
|
33
|
+
.mc-recent-body
|
34
|
+
%div
|
35
|
+
- if comment.author_name
|
36
|
+
= link_to comment.author_www, target: '_blank' do
|
37
|
+
%span.mc-recent-author= comment.author_name
|
38
|
+
- else
|
39
|
+
%span.mc-recent-author= comment.anonym_name
|
40
|
+
%p.mc-recent-text= link_to comment.message.truncate(@config['recent']['mcTextSize']), comment.url + "#mc-#{comment.id}"
|
41
|
+
%p.mc-recent-meta
|
42
|
+
= link_to comment.title.truncate(@config['recent']['mcTitleSize']), comment.url, title: comment.title
|
43
|
+
- unless 1.month.ago > (date = comment.created_at)
|
44
|
+
· #{time_ago_in_words date} назад
|
45
|
+
- else
|
46
|
+
· #{date.strftime("%d.%m")}
|
47
|
+
= date.strftime("%H:%M")
|
48
|
+
|
49
|
+
:javascript
|
50
|
+
var mcSite = '#{@config['site_id']}';
|
51
|
+
var mcSize = '#{@config['recent']['mcSize']}';
|
52
|
+
var mcAvatarSize = '#{@config['recent']['mcAvatarSize']}';;
|
53
|
+
var mcTextSize = '#{@config['recent']['mcTextSize']}';
|
54
|
+
var mcTitleSize = '#{@config['recent']['mcTitleSize']}';
|
55
|
+
var mcJqueryOff = #{@config['recent']['mcJqueryOff']};
|
56
|
+
(function() {
|
57
|
+
var mc = document.createElement('script');
|
58
|
+
mc.type = 'text/javascript';
|
59
|
+
mc.async = true;
|
60
|
+
mc.src = 'http://cackle.me/mc.last-min.js';
|
61
|
+
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(mc);
|
62
|
+
})();
|
data/lib/cackle.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Cackle
|
2
|
+
require "cackle/railtie" if defined?(Rails)
|
3
|
+
require 'app/helpers/cackle_helper'
|
4
|
+
|
5
|
+
ActionView::Base.send :include, CackleHelper
|
6
|
+
|
7
|
+
path = File.join(File.dirname(__FILE__), 'app', 'models')
|
8
|
+
$LOAD_PATH << path
|
9
|
+
ActiveSupport::Dependencies.autoload_paths << path
|
10
|
+
ActiveSupport::Dependencies.autoload_once_paths.delete(path)
|
11
|
+
|
12
|
+
ActionController::Base.prepend_view_path File.join(File.dirname(__FILE__), 'app/views')
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CackleMigrationGenerator < Rails::Generators::Base
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
|
8
|
+
def self.next_migration_number(dirname)
|
9
|
+
if ActiveRecord::Base.timestamped_migrations
|
10
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
11
|
+
else
|
12
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_migration_file
|
17
|
+
migration_template 'migration.rb', 'db/migrate/create_cackle_comments.rb'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateCackleComments < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :cackle_comments, id: false do |t|
|
4
|
+
t.integer :comment_id
|
5
|
+
t.integer :parent_id
|
6
|
+
t.string :post_id
|
7
|
+
t.string :url
|
8
|
+
t.string :title
|
9
|
+
t.text :message
|
10
|
+
t.string :status
|
11
|
+
t.string :ip
|
12
|
+
t.string :author_name
|
13
|
+
t.string :author_email
|
14
|
+
t.string :author_avatar
|
15
|
+
t.string :author_www
|
16
|
+
t.string :author_provider
|
17
|
+
t.string :anonym_name
|
18
|
+
t.string :anonym_email
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
namespace :cackle do
|
4
|
+
def load_config
|
5
|
+
@config = YAML::load(File.open('config/cackle.yml'))
|
6
|
+
@path = "http://cackle.me/api/comment/mutable_list?siteApiKey=#{@config['site_api_key']}&accountApiKey=#{@config['account_api_key']}"
|
7
|
+
raise "Create config/cackle.yml first" unless @config
|
8
|
+
|
9
|
+
puts "will use: "
|
10
|
+
puts @config['site_id']
|
11
|
+
puts @config['site_api_key']
|
12
|
+
puts @config['account_api_key']
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_comment c
|
16
|
+
comment = CackleComment.new(
|
17
|
+
comment_id: c['id'],
|
18
|
+
parent_id: c['parentId'],
|
19
|
+
post_id: c['channel'],
|
20
|
+
url: c['url'],
|
21
|
+
title: c['title'],
|
22
|
+
message: c['message'],
|
23
|
+
status: c['status'],
|
24
|
+
ip: c['ip'],
|
25
|
+
created_at: Time.strptime((c['created']/1000).to_s, "%s"),
|
26
|
+
updated_at: Time.strptime(c['modified'][0..9], "%s"))
|
27
|
+
if c['author']
|
28
|
+
comment.author_name = c['author']['name']
|
29
|
+
comment.author_email = c['author']['email']
|
30
|
+
comment.author_www = c['author']['www']
|
31
|
+
comment.author_avatar = c['author']['avatar']
|
32
|
+
comment.author_provider = c['author']['provider']
|
33
|
+
else
|
34
|
+
comment.anonym_name = c['anonym']['name']
|
35
|
+
comment.anonym_email = c['anonym']['email']
|
36
|
+
end
|
37
|
+
if comment.save
|
38
|
+
puts "created #{comment.comment_id}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Initial comment base load'
|
43
|
+
task import: :environment do
|
44
|
+
CackleComment.delete_all
|
45
|
+
load_config
|
46
|
+
begin
|
47
|
+
max = CackleComment.maximum('created_at')
|
48
|
+
@url = max ? @path + "&modified=#{max.to_i*1000}" : @path
|
49
|
+
response = open(@url).read
|
50
|
+
json = JSON.parse(response)
|
51
|
+
comments = json['comments']
|
52
|
+
comments.each do |c|
|
53
|
+
create_comment c
|
54
|
+
end
|
55
|
+
end while (comments.size == 100)
|
56
|
+
puts "Total #{CackleComment.count} in base"
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Synchronize comments database'
|
60
|
+
task sync: :environment do
|
61
|
+
load_config
|
62
|
+
|
63
|
+
max = CackleComment.maximum('updated_at')
|
64
|
+
raise "run bootstrap first" unless max
|
65
|
+
|
66
|
+
puts "maximum found in base: #{max}"
|
67
|
+
@url = @path + "&modified=#{max.to_i*1000}"
|
68
|
+
|
69
|
+
response = open(@url).read
|
70
|
+
json = JSON.parse(response)
|
71
|
+
|
72
|
+
json['comments'].each do |c|
|
73
|
+
comment = CackleComment.find_by_comment_id(c['id'])
|
74
|
+
if comment
|
75
|
+
if (time = Time.strptime((c['modified'][0..9]).to_s, "%s")) > comment.updated_at
|
76
|
+
puts "updating: #{c['id']}"
|
77
|
+
comment.update_attributes(
|
78
|
+
message: c['message'],
|
79
|
+
status: c['status'],
|
80
|
+
updated_at: time)
|
81
|
+
comment.save
|
82
|
+
else
|
83
|
+
puts "comment: #{c['id']} already exist"
|
84
|
+
end
|
85
|
+
else
|
86
|
+
create_comment c
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/test/cackle_test.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|