cowtech-rails 2.2.3.3 → 2.3.0.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/lib/cowtech.rb +7 -0
- data/lib/cowtech/tasks/app.rake +116 -0
- data/lib/cowtech/tasks/log.rake +77 -0
- data/lib/cowtech/tasks/mongodb.rake +5 -0
- data/lib/cowtech/tasks/server.rake +107 -0
- data/lib/cowtech/tasks/sql.rake +113 -0
- data/lib/cowtech/version.rb +3 -3
- metadata +10 -5
data/lib/cowtech.rb
CHANGED
@@ -14,6 +14,13 @@ require 'cowtech/monkey_patches'
|
|
14
14
|
|
15
15
|
module Cowtech
|
16
16
|
class Engine < Rails::Engine
|
17
|
+
rake_tasks do
|
18
|
+
load "cowtech/tasks/app.rake"
|
19
|
+
load "cowtech/tasks/log.rake"
|
20
|
+
load "cowtech/tasks/server.rake"
|
21
|
+
load "cowtech/tasks/sql.rake"
|
22
|
+
load "cowtech/tasks/mongodb.rake"
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the cowtech-rails gem. Copyright (C) 2011 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Cowtech
|
8
|
+
module RubyOnRails
|
9
|
+
class AppUtils
|
10
|
+
def self.run_command(cmd)
|
11
|
+
IO.popen(cmd, "r") do |f| puts f.gets end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.get_version(as_string = true)
|
15
|
+
info = YAML.load_file(Rails.root + "config/application_info.yml")
|
16
|
+
(if as_string then "Current application info --- Version #{info["version"]} - Release date: #{info["release-date"]}" else info end)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.set_version(info)
|
20
|
+
puts "--- Setting application version ..."
|
21
|
+
File.open(Rails.root + "config/application_info.yml", "w") do |f| f.write(info.to_yaml) end
|
22
|
+
puts Cowtech::RubyOnRails::AppUtils.get_version
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.tag
|
26
|
+
info = Cowtech::RubyOnRails::AppUtils.get_version(false)
|
27
|
+
tag = "v-#{info["version"]}"
|
28
|
+
puts "--- Tagging current version as tag #{tag}"
|
29
|
+
Cowtech::RubyOnRails::AppUtils.run_command("git tag -f #{tag}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.commit(msg)
|
33
|
+
# Commit data
|
34
|
+
puts "--- Adding data to repository..."
|
35
|
+
Cowtech::RubyOnRails::AppUtils.run_command("git add .")
|
36
|
+
|
37
|
+
puts "--- Commiting changes ..."
|
38
|
+
Cowtech::RubyOnRails::AppUtils.run_command("git commit -a --allow-empty-message -m \"#{msg}\"")
|
39
|
+
puts "--- Checking repository status ..."
|
40
|
+
Cowtech::RubyOnRails::AppUtils.run_command("git status")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.push
|
44
|
+
puts "--- Pushing to server ..."
|
45
|
+
run_command("git push alpha")
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.clear_cache
|
49
|
+
puts "--- Clearing rails cache ..."
|
50
|
+
Rails.cache.clear
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
namespace :app do
|
57
|
+
namespace :version do
|
58
|
+
desc "Get application info"
|
59
|
+
task :get do |task|
|
60
|
+
puts Cowtech::RubyOnRails::AppUtils.get_version
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "Set application info"
|
64
|
+
task :set, :version do |task, args|
|
65
|
+
if args[:version] then
|
66
|
+
Cowtech::RubyOnRails::AppUtils.set_version({"version" => args[:version], "release-date" => Time.now.strftime("%Y-%m-%d")})
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Clears all Rails cache"
|
72
|
+
task :clear_cache => :environment do |task|
|
73
|
+
Cowtech::RubyOnRails::AppUtils.clear_cache
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Set application info, add all files and commits to git"
|
77
|
+
task :commit, :message, :version do |task, args|
|
78
|
+
args[:message] ||= ""
|
79
|
+
|
80
|
+
Cowtech::RubyOnRails::AppUtils.set_version({"version" => args[:version], "release-date" => Time.now.strftime("%Y-%m-%d")}) if args[:version].present?
|
81
|
+
Cowtech::RubyOnRails::AppUtils.commit(args[:message])
|
82
|
+
Cowtech::RubyOnRails::AppUtils.tag if args[:version].present?
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "Commit application and then push it to server"
|
86
|
+
task :push, :message, :version do |task, args|
|
87
|
+
Cowtech::RubyOnRails::AppUtils.set_version({"version" => args[:version], "release-date" => Time.now.strftime("%Y-%m-%d")}) if args[:version].present?
|
88
|
+
Cowtech::RubyOnRails::AppUtils.commit(args[:message])
|
89
|
+
Cowtech::RubyOnRails::AppUtils.tag if args[:version].present?
|
90
|
+
Cowtech::RubyOnRails::AppUtils.push
|
91
|
+
end
|
92
|
+
|
93
|
+
desc "Tags current application version in git"
|
94
|
+
task :tag do |task|
|
95
|
+
Cowtech::RubyOnRails::AppUtils.tag
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
namespace :css do
|
100
|
+
desc "Regenerating CSS..."
|
101
|
+
task :regenerate => :environment do |task|
|
102
|
+
puts "Regenerating CSS..."
|
103
|
+
|
104
|
+
if defined?(Less) then # MORE
|
105
|
+
puts "Using More"
|
106
|
+
Rake::Task["more:clean"].execute
|
107
|
+
Rake::Task["more:generate"].execute
|
108
|
+
elsif defined?(Sass) # SASS
|
109
|
+
Sass::Plugin.on_updating_stylesheet do |template, css|
|
110
|
+
puts "[SCSS] Compiling #{template} to #{css} ..."
|
111
|
+
end
|
112
|
+
|
113
|
+
Sass::Plugin.force_update_stylesheets
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the cowtech-rails gem. Copyright (C) 2011 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Cowtech
|
8
|
+
module RubyOnRails
|
9
|
+
class LogUtils
|
10
|
+
@@log_compressor_command = "bzip2"
|
11
|
+
@@log_compressed_extension = "bz2"
|
12
|
+
|
13
|
+
def self.generate_new_name(base, i = 0); "#{base}#{if i > 0 then "-#{i}" else "" end}" end
|
14
|
+
|
15
|
+
def self.run_command(cmd)
|
16
|
+
IO.popen(cmd) do |f| print f.gets end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.rotate
|
20
|
+
puts "Rotating log files..."
|
21
|
+
|
22
|
+
# Get timestamp
|
23
|
+
tstamp = Time.now.strftime("%Y%m%d")
|
24
|
+
|
25
|
+
# For each log file
|
26
|
+
Dir.glob(Rails.root + "log/*.log") do |log_file|
|
27
|
+
puts "\tRotating #{log_file} ..."
|
28
|
+
new_name = "#{log_file}-#{tstamp}" # CREIAMO IL NOME
|
29
|
+
|
30
|
+
# Resolv duplicates
|
31
|
+
i = 0
|
32
|
+
i += 1 while File.exists?("#{generate_new_name(new_name, i)}.#{@@log_compressed_extension}")
|
33
|
+
new_file = generate_new_name(new_name, i)
|
34
|
+
|
35
|
+
# Send file via mail
|
36
|
+
@email_class = defined?(Common::EMail) ? Common::EMail : EMail
|
37
|
+
@email_class.log_report(log_file).deliver if Rails.env == "production"
|
38
|
+
|
39
|
+
# Copy file
|
40
|
+
FileUtils.cp(log_file, new_file)
|
41
|
+
|
42
|
+
# BZIPPIAMO IL FILE
|
43
|
+
system(@@log_compressor_command, new_file)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Truncate files
|
47
|
+
puts "Truncating current log files ..."
|
48
|
+
Dir.glob(Rails.root + "log/*.log") do |log_file|
|
49
|
+
File.open(log_file, "w").close
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.clean
|
54
|
+
puts "Cleaning log files..."
|
55
|
+
|
56
|
+
["log/*.log", "log/*.#{@@log_compressed_extension}"].each do |path|
|
57
|
+
Dir.glob(Rails.root + path) do |log_file|
|
58
|
+
puts "\tDeleting #{log_file.gsub(Rails.root.to_s + "/", "")} ..."
|
59
|
+
File.delete(log_file)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
namespace :log do
|
68
|
+
desc "Rotates log files"
|
69
|
+
task :rotate => :environment do |task|
|
70
|
+
Cowtech::RubyOnRails::LogUtils.rotate
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "Clean every log file"
|
74
|
+
task :clean do |task|
|
75
|
+
Cowtech::RubyOnRails::LogUtils.clean
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the cowtech-rails gem. Copyright (C) 2011 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Cowtech
|
8
|
+
module RubyOnRails
|
9
|
+
class ServerUtils
|
10
|
+
@@yml_path = "config/server.yml"
|
11
|
+
@@config = nil
|
12
|
+
|
13
|
+
def self.thin_path; "config/thin.yml"; end
|
14
|
+
def self.default_environment; "development"; end
|
15
|
+
|
16
|
+
def self.load_config(force = false)
|
17
|
+
begin
|
18
|
+
@@config = YAML.load_file(Rails.root + @@yml_path) if @@config == nil || force == true
|
19
|
+
rescue
|
20
|
+
@@config = []
|
21
|
+
end
|
22
|
+
@@config
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.save_config(args = nil)
|
26
|
+
args = Cowtech::RubyOnRails::ServerUtils.load_config if !args
|
27
|
+
File.open(Rails.root + @@yml_path, "w") do |f| f.write(YAML::dump(args)) end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.stringify_keys(hash)
|
31
|
+
rv = {}
|
32
|
+
hash.each do |k, v| rv[k.to_s] = v end
|
33
|
+
rv
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.merge(base, other)
|
37
|
+
rv = {}
|
38
|
+
base.each do |k, v| rv[k] = if other[k] then other[k] else v end end
|
39
|
+
rv
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.run_command(cmd)
|
43
|
+
system(cmd)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Cowtech::RubyOnRails::ThinServer < Cowtech::RubyOnRails::ServerUtils
|
48
|
+
def self.prepare(rake_args)
|
49
|
+
self.load_config
|
50
|
+
Cowtech::RubyOnRails::ThinServer.merge(@@config["thin"], Cowtech::RubyOnRails::ThinServer.stringify_keys(rake_args))
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.start(rake_args)
|
54
|
+
args = self.prepare(rake_args)
|
55
|
+
@@config["thin"] = args
|
56
|
+
Cowtech::RubyOnRails::ThinServer.save_config
|
57
|
+
puts "--- Starting thin server with config file #{args["config"]} in environment #{args["environment"]}..."
|
58
|
+
Cowtech::RubyOnRails::ThinServer.execute("start", args["config"], args["environment"])
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.stop(rake_args)
|
62
|
+
args = self.prepare(rake_args)
|
63
|
+
puts "--- Stopping Thin server ..."
|
64
|
+
Cowtech::RubyOnRails::ThinServer.execute("stop", args["config"], args["environment"])
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.restart(rake_args)
|
68
|
+
args = self.prepare(rake_args)
|
69
|
+
puts "--- Restarting thin server with config file #{args["config"]} in environment #{args["environment"]}..."
|
70
|
+
Cowtech::RubyOnRails::ThinServer.execute("restart", args["config"], args["environment"])
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.execute(command, config, environment)
|
74
|
+
run_command("thin -C #{config} -e #{environment} #{command}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.test
|
78
|
+
puts "--- Testing thin server in the foreground"
|
79
|
+
run_command("thin start")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
namespace :server do
|
86
|
+
namespace :thin do
|
87
|
+
desc "Starts Thin server"
|
88
|
+
task :start, ["environment", "config"], do |task, rake_args|
|
89
|
+
Cowtech::RubyOnRails::ThinServer.start(rake_args.with_defaults("config" => Cowtech::RubyOnRails::ServerUtils.thin_path, "environment" => Cowtech::RubyOnRails::ServerUtils.default_environment))
|
90
|
+
end
|
91
|
+
|
92
|
+
desc "Stops Thin server"
|
93
|
+
task :stop, ["environment", "config"] do |task, rake_args|
|
94
|
+
Cowtech::RubyOnRails::ThinServer.stop(rake_args.with_defaults("config" => nil, "environment" => nil))
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "Restarts Thin server"
|
98
|
+
task :restart, ["environment", "config"] do |task, rake_args|
|
99
|
+
Cowtech::RubyOnRails::ThinServer.restart(rake_args.with_defaults("config" => nil, "environment" => nil))
|
100
|
+
end
|
101
|
+
|
102
|
+
desc "Tests Thin server into the foreground"
|
103
|
+
task :test do |task|
|
104
|
+
Cowtech::RubyOnRails::ThinServer.test
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the cowtech-rails gem. Copyright (C) 2011 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Cowtech
|
8
|
+
module RubyOnRails
|
9
|
+
class MysqlUtils
|
10
|
+
@@log_compressor_command = "bzip2"
|
11
|
+
@@log_compressed_extension = "bz2"
|
12
|
+
|
13
|
+
def self.run_command(cmd); system(cmd) end
|
14
|
+
|
15
|
+
def self.mysql_execute(config)
|
16
|
+
dest_file = Rails.root + "db/backup/db-#{Time.now.strftime("%Y%m%d-%H%M%S")}.sql"
|
17
|
+
|
18
|
+
dump_cmd = "mysqldump"
|
19
|
+
dump_args = {"" => "-R -r \"#{dest_file}\"", "host" => "-h @@ARG@@", "username" => "-u @@ARG@@", "password" => "--password=\"@@ARG@@\"", "database" => "@@ARG@@"}
|
20
|
+
|
21
|
+
# Build command
|
22
|
+
args = dump_args.dup
|
23
|
+
args.keys.each do |k|
|
24
|
+
if k == "" || config[k] then
|
25
|
+
args[k].gsub!("@@ARG@@", config[k] || "")
|
26
|
+
else
|
27
|
+
args.delete(k)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create directory
|
32
|
+
dir = File.dirname(dest_file)
|
33
|
+
FileUtils.mkdir(dir) if !File.directory?(dir)
|
34
|
+
|
35
|
+
# Execute command
|
36
|
+
puts "\tDumping data ..."
|
37
|
+
Cowtech::RubyOnRails::MysqlUtils.run_command(dump_cmd + " " + dump_args.values.join(" "))
|
38
|
+
|
39
|
+
# Compress
|
40
|
+
puts "\tCompressing backup ..."
|
41
|
+
Cowtech::RubyOnRails::MysqlUtils.run_command(@@log_compressor_command + " " + dest_file.to_s)
|
42
|
+
|
43
|
+
puts "Backup saved in #{dest_file}.#{@@log_compressed_extension}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# ALIAS
|
47
|
+
class << self
|
48
|
+
alias_method :mysql2_execute, :mysql_execute
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Cowtech::RubyOnRails::SqlUtils
|
53
|
+
@@log_compressor_command = "bzip2"
|
54
|
+
@@log_compressed_extension = "bz2"
|
55
|
+
|
56
|
+
def self.to_fixtures
|
57
|
+
puts "--- Dumping database into fixtures ..."
|
58
|
+
sql = "SELECT * FROM %s"
|
59
|
+
skip_tables = ["schema_info"]
|
60
|
+
ActiveRecord::Base.establish_connection
|
61
|
+
(ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|
|
62
|
+
puts "--- --- Dumping table #{table_name} ..."
|
63
|
+
i = "01"
|
64
|
+
File.open("#{RAILS_ROOT}/test/fixture/#{table_name}.yml", 'w') do |file|
|
65
|
+
data = ActiveRecord::Base.connection.select_all(sql % table_name)
|
66
|
+
file.write data.inject({}) { |hash, record|
|
67
|
+
hash["#{table_name}_#{i.succ!}"] = record
|
68
|
+
hash
|
69
|
+
}.to_yaml
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.backup
|
75
|
+
puts "--- Backupping database ..."
|
76
|
+
# OTTENIAMO LA CONFIGURAZIONE
|
77
|
+
db_config = YAML.load_file(Rails.root + "config/database.yml")
|
78
|
+
env = Rails.env
|
79
|
+
|
80
|
+
# ESEGUIAMO
|
81
|
+
Cowtech::RubyOnRails::MysqlUtils.send("#{db_config[env]["adapter"]}_execute", db_config[env])
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.backup_clean
|
85
|
+
puts "--- Cleaning database backup files ..."
|
86
|
+
|
87
|
+
["db/backup/*.sql", "db/backup/*.#{@@log_compressed_extension}"].each do |path|
|
88
|
+
Dir.glob(Rails.root + path) do |log_file|
|
89
|
+
puts "\tDeleting #{log_file.gsub(Rails.root.to_s + "/", "")} ..."
|
90
|
+
File.delete(log_file)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
namespace :mysql do
|
99
|
+
desc 'Converting data to fixtures'
|
100
|
+
task :to_fixtures => :environment do
|
101
|
+
Cowtech::RubyOnRails::SqlUtils.to_fixtures
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "Backups database"
|
105
|
+
task :backup do |task|
|
106
|
+
Cowtech::RubyOnRails::SqlUtils.backup
|
107
|
+
end
|
108
|
+
|
109
|
+
desc "Clean every backup file"
|
110
|
+
task :backup_clean do |task|
|
111
|
+
Cowtech::RubyOnRails::SqlUtils.backup_clean
|
112
|
+
end
|
113
|
+
end
|
data/lib/cowtech/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cowtech-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-11-16 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cowtech-extensions
|
16
|
-
requirement: &
|
16
|
+
requirement: &70292397406760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70292397406760
|
25
25
|
description: A general purpose Rails utility plugin.
|
26
26
|
email: shogun_panda@me.com
|
27
27
|
executables: []
|
@@ -43,6 +43,11 @@ files:
|
|
43
43
|
- lib/cowtech.rb
|
44
44
|
- lib/cowtech/extensions.rb
|
45
45
|
- lib/cowtech/monkey_patches.rb
|
46
|
+
- lib/cowtech/tasks/app.rake
|
47
|
+
- lib/cowtech/tasks/log.rake
|
48
|
+
- lib/cowtech/tasks/mongodb.rake
|
49
|
+
- lib/cowtech/tasks/server.rake
|
50
|
+
- lib/cowtech/tasks/sql.rake
|
46
51
|
- lib/cowtech/version.rb
|
47
52
|
- rails/init.rb
|
48
53
|
- README
|
@@ -67,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
72
|
version: '0'
|
68
73
|
requirements: []
|
69
74
|
rubyforge_project:
|
70
|
-
rubygems_version: 1.8.
|
75
|
+
rubygems_version: 1.8.11
|
71
76
|
signing_key:
|
72
77
|
specification_version: 3
|
73
78
|
summary: A general purpose Rails utility plugin.
|