findex 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.markdown +55 -0
- data/Rakefile +17 -0
- data/VERSION +1 -0
- data/findex.gemspec +41 -0
- data/lib/findex/tasks.rb +261 -0
- data/spec/findex_tasks_spec.rb +51 -0
- metadata +61 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Flip Sasser
|
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.markdown
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Findex #
|
2
|
+
|
3
|
+
Findex is a simple collection of Rake tasks that will help you locate missing database indexes in your Rails app. It can also generate migrations and run them, as well as filter by specific column types, names, and tables.
|
4
|
+
|
5
|
+
**Please note** that Findex designed to find any potentially overlooked indexes. It is not a good practice to index every matching column it returns - that's way too many.
|
6
|
+
|
7
|
+
## Installation ##
|
8
|
+
|
9
|
+
Install Findex as a gem:
|
10
|
+
|
11
|
+
$ gem install findex --source=http://gems.github.com
|
12
|
+
|
13
|
+
You may want to configure it as a gem in environment.rb instead, since you're going to need it in your Rakefile:
|
14
|
+
|
15
|
+
config.gem 'findex', :source => 'http://gemcutter.org'
|
16
|
+
|
17
|
+
... then run:
|
18
|
+
|
19
|
+
rake gems:install
|
20
|
+
|
21
|
+
In either case. open your Rails app's Rakefile and add the following line:
|
22
|
+
|
23
|
+
require 'findex/tasks'
|
24
|
+
|
25
|
+
And it's installed. Bam.
|
26
|
+
|
27
|
+
## Find Missing Indexes ##
|
28
|
+
|
29
|
+
First, get some instructions:
|
30
|
+
|
31
|
+
$ rake db:indexes:help
|
32
|
+
|
33
|
+
rake db:indexes will generate a list of indexes your application's database may or may not need.
|
34
|
+
|
35
|
+
To see a list of all indexes it thinks you need, just use rake db:indexes
|
36
|
+
|
37
|
+
You can add migration=true to generate a migration file
|
38
|
+
or perform=true to perform the indexing immediately:
|
39
|
+
`rake db:indexes migration=true`
|
40
|
+
|
41
|
+
You can also target specific column types, like so:
|
42
|
+
`rake db:indexes:boolean`
|
43
|
+
`rake db:indexes:datetime`
|
44
|
+
`rake db:indexes:geo`
|
45
|
+
`rake db:indexes:primary`
|
46
|
+
`rake db:indexes:relationships`
|
47
|
+
|
48
|
+
You can also filter by column names and types, or by whole tables:
|
49
|
+
`rake db:indexes:names names=type,state`
|
50
|
+
`rake db:indexes:types types=integer,decimal`
|
51
|
+
`rake db:indexes tables=users,posts`
|
52
|
+
|
53
|
+
Read the instructions above and start finding missing indexes! Thanks to Matt Janowski for the inspiration (http://robots.thoughtbot.com/post/163627511/a-grand-piano-for-your-violin) and Thoughtbot / Jon Yurek for the core of the indexes detection code!
|
54
|
+
|
55
|
+
Copyright (c) 2009 Flip Sasser, released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gemspec|
|
8
|
+
gemspec.name = "findex"
|
9
|
+
gemspec.summary = "Rake tasks to check your Rails models for missing indexes"
|
10
|
+
gemspec.description = ""
|
11
|
+
gemspec.email = "flip@x451.com"
|
12
|
+
gemspec.homepage = "http://github.com/flipsasser/findex"
|
13
|
+
gemspec.authors = ["Flip Sasser"]
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/findex.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{findex}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Flip Sasser"]
|
12
|
+
s.date = %q{2009-11-12}
|
13
|
+
s.description = %q{}
|
14
|
+
s.email = %q{flip@x451.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.markdown"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"MIT-LICENSE",
|
20
|
+
"README.markdown",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"tasks/db/indexes.rake"
|
24
|
+
]
|
25
|
+
s.homepage = %q{http://github.com/flipsasser/findex}
|
26
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
s.rubygems_version = %q{1.3.5}
|
29
|
+
s.summary = %q{Rake tasks to check your Rails models for missing indexes}
|
30
|
+
|
31
|
+
if s.respond_to? :specification_version then
|
32
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
33
|
+
s.specification_version = 3
|
34
|
+
|
35
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
36
|
+
else
|
37
|
+
end
|
38
|
+
else
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
data/lib/findex/tasks.rb
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/tasklib'
|
4
|
+
|
5
|
+
namespace :db do
|
6
|
+
desc 'Finds indexes your application probably needs'
|
7
|
+
task :indexes => [:environment, :prepare] do
|
8
|
+
indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
|
9
|
+
Findex.send_indices(indices)
|
10
|
+
end
|
11
|
+
|
12
|
+
task :prepare do
|
13
|
+
@generate_migration = ENV['migration'] == 'true'
|
14
|
+
@perform_index = ENV['perform'] == 'true'
|
15
|
+
@tables = ENV['tables'] ? ENV['tables'].split(',').map(&:strip) : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :indexes do
|
19
|
+
desc 'Finds unindexed boolean columns'
|
20
|
+
task :boolean => [:environment, :prepare] do
|
21
|
+
@migration_name = 'boolean'
|
22
|
+
Findex.send_indices(Findex.get_indices([:type, [:boolean]]))
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Finds unindexed date, time, and datetime columns'
|
26
|
+
task :datetime => [:environment, :prepare] do
|
27
|
+
@migration_name = 'datetime'
|
28
|
+
Findex.send_indices(Findex.get_indices([:type, [:date, :datetime, :time]]))
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Finds unindexed geo columns'
|
32
|
+
task :geo => [:environment, :prepare] do
|
33
|
+
@migration_name = 'geo'
|
34
|
+
Findex.send_indices(Findex.get_indices(:geo))
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Prints instructions on how to use rake:db:indexes'
|
38
|
+
task :help do
|
39
|
+
puts ''
|
40
|
+
puts " rake db:indexes will generate a list of indexes your application's database may or may not need."
|
41
|
+
puts ''
|
42
|
+
puts ' To see a list of all indexes it thinks you need, just use rake db:indexes'
|
43
|
+
puts ''
|
44
|
+
puts " You can add migration=true to generate a migration file\n or perform=true to perform the indexing immediately:"
|
45
|
+
puts ' `rake db:indexes migration=true`'
|
46
|
+
puts ''
|
47
|
+
puts ' You can also target specific column types, like so:'
|
48
|
+
for type in [:boolean, :datetime, :geo, :primary, :relationships]
|
49
|
+
puts " `rake db:indexes:#{type}`"
|
50
|
+
end
|
51
|
+
puts ''
|
52
|
+
puts ' You can also filter by column names and types, or by whole tables:'
|
53
|
+
puts ' `rake db:indexes:names names=type,state`'
|
54
|
+
puts ' `rake db:indexes:types types=integer,decimal`'
|
55
|
+
puts ' `rake db:indexes tables=users,posts`'
|
56
|
+
puts ''
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Generates a migration file with the recommended indexes'
|
60
|
+
task :migration => :environment do
|
61
|
+
@generate_migration = true
|
62
|
+
@perform_index = false
|
63
|
+
indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
|
64
|
+
Findex.send_indices(indices)
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Finds unindexed columns matching the names you supply'
|
68
|
+
task :names => [:environment, :prepare] do
|
69
|
+
if ENV['names']
|
70
|
+
indices = Findex.get_indices([:name, ENV['names'].split(',').map(&:strip).map(&:intern)])
|
71
|
+
Findex.send_indices(indices)
|
72
|
+
else
|
73
|
+
puts ''
|
74
|
+
puts ' You must pass in a comma-separated collection of names like so'
|
75
|
+
puts ' `rake db:indexes:names names=type,state`'
|
76
|
+
puts ''
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'Performs a migration with the recommended indexes'
|
81
|
+
task :perform => :environment do
|
82
|
+
@generate_migration = false
|
83
|
+
@perform_index = true
|
84
|
+
indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
|
85
|
+
Findex.send_indices(indices)
|
86
|
+
end
|
87
|
+
|
88
|
+
desc 'Finds unindexed primary keys'
|
89
|
+
task :primary => [:environment, :prepare] do
|
90
|
+
@migration_name = 'primary'
|
91
|
+
Findex.send_indices(Findex.get_indices(:primary))
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'Finds unindexed relationship foreign keys'
|
95
|
+
task :relationships => [:environment, :prepare] do
|
96
|
+
@migration_name = 'relationship'
|
97
|
+
Findex.send_indices(Findex.get_indices(:reflection))
|
98
|
+
end
|
99
|
+
|
100
|
+
desc 'Finds unindexed columns matching the types you supply'
|
101
|
+
task :types => [:environment, :prepare] do
|
102
|
+
if ENV['types']
|
103
|
+
indices = Findex.get_indices([:type, ENV['types'].split(',').map(&:strip).map(&:intern)])
|
104
|
+
Findex.send_indices(indices)
|
105
|
+
else
|
106
|
+
puts ''
|
107
|
+
puts ' You must pass in a comma-separated collection of types like so'
|
108
|
+
puts ' `rake db:indexes:types types=integer,decimal`'
|
109
|
+
puts ''
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
module Findex
|
117
|
+
def self.check_index(*args)
|
118
|
+
index = args.shift
|
119
|
+
!args.any?{|array| array.any?{|comparison_index| comparison_index == index}}
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.collect_indices(indices)
|
123
|
+
indices.collect{|table, columns| [table, columns.sort{|a, b|
|
124
|
+
if a == :id
|
125
|
+
-1
|
126
|
+
elsif b == :id
|
127
|
+
1
|
128
|
+
else
|
129
|
+
(a.is_a?(Array) ? a.map(&:to_s).join('_') : a.to_s) <=> (b.is_a?(Array) ? b.map(&:to_s).join('_') : b.to_s)
|
130
|
+
end
|
131
|
+
}]}.sort{|a, b| a[0].to_s <=> b[0].to_s}
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.connection
|
135
|
+
@connection ||= ActiveRecord::Base.connection
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.get_indices(*args)
|
139
|
+
indices = {}
|
140
|
+
ObjectSpace.each_object(Class) do |model|
|
141
|
+
next unless model.ancestors.include?(ActiveRecord::Base) && model != ActiveRecord::Base && model.table_exists?
|
142
|
+
next if @tables && !@tables.include?(model.table_name.to_s)
|
143
|
+
existing_indices = connection.indexes(model.table_name).map{|index| index.columns.length == 1 ? index.columns.first.to_sym : index.columns.map(&:to_sym) }
|
144
|
+
args.each do |method, options|
|
145
|
+
indices = send("get_model_#{method}_indices", *[model, options, indices, existing_indices].compact)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
collect_indices(indices)
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.get_model_geo_indices(model, indices, existing_indices)
|
152
|
+
indices[model.table_name] ||= []
|
153
|
+
parse_columns(model) do |column, column_name|
|
154
|
+
if column.type == :decimal && column.name =~ /(lat|lng)/ && model.column_names.include?(alternate_column_name = column.name.gsub(/(^|_)(lat|lng)($|_)/) { "#{$1}#{$2 == 'lat' ? 'lng' : 'lat'}#{$3}"})
|
155
|
+
index = [column_name, alternate_column_name.to_sym]
|
156
|
+
indices[model.table_name].push([column_name, alternate_column_name.to_sym]) if check_index(index, indices[model.table_name], existing_indices)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
indices
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.get_model_name_indices(model, names, indices, existing_indices)
|
163
|
+
indices[model.table_name] ||= []
|
164
|
+
parse_columns(model) do |column, column_name|
|
165
|
+
if names.include?(column_name) && check_index(column_name, indices[model.table_name], existing_indices)
|
166
|
+
indices[model.table_name].push(column_name)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
indices
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.get_model_primary_indices(model, indices, existing_indices)
|
173
|
+
indices[model.table_name] ||= []
|
174
|
+
parse_columns(model) do |column, column_name|
|
175
|
+
if column.primary && check_index(column_name, indices[model.table_name], existing_indices)
|
176
|
+
indices[model.table_name].push(column_name)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
indices
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.get_model_reflection_indices(model, indices, existing_indices)
|
183
|
+
indices[model.table_name] ||= []
|
184
|
+
for name, reflection in model.reflections
|
185
|
+
case reflection.macro.to_sym
|
186
|
+
when :belongs_to
|
187
|
+
foreign_key = reflection.primary_key_name.to_sym
|
188
|
+
indices[model.table_name].push(foreign_key) if check_index(foreign_key, indices[model.table_name], existing_indices)
|
189
|
+
when :has_and_belongs_to_many
|
190
|
+
index = [reflection.primary_key_name.to_sym, reflection.association_foreign_key.to_sym]
|
191
|
+
if (table_name = reflection.options[:join_table] || reflection.options['join_table']) && connection.table_exists?(table_name)
|
192
|
+
indices[table_name] ||= []
|
193
|
+
unless indices[table_name].any?{|existing_index| existing_index == index} || connection.indexes(table_name).map{|join_index| join_index.columns.length == 1 ? join_index.columns.first.to_sym : join_index.columns.map(&:to_sym) }.any?{|existing_index| existing_index == index}
|
194
|
+
indices[table_name].push(index)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
indices
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.get_model_type_indices(model, types, indices, existing_indices)
|
203
|
+
indices[model.table_name] ||= []
|
204
|
+
parse_columns(model) do |column, column_name|
|
205
|
+
if types.include?(column.type) && check_index(column_name, indices[model.table_name], existing_indices)
|
206
|
+
indices[model.table_name].push(column_name)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
indices
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.parse_columns(model)
|
213
|
+
model.columns.each{|column| yield(column, column.name.to_sym)} if block_given?
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.send_indices(indices)
|
217
|
+
if @generate_migration
|
218
|
+
require 'rails_generator'
|
219
|
+
migration_path = File.join(RAILS_ROOT, 'db', 'migrate')
|
220
|
+
migration_number = 1
|
221
|
+
migration_test = "add#{"_#{@migration_name}" if @migration_name}_indexes"
|
222
|
+
for file in Dir[File.join(migration_path, '*.rb')]
|
223
|
+
file = File.basename(file)
|
224
|
+
next unless file =~ /^\d+_#{migration_test}(\d+)\.rb$/
|
225
|
+
migration_number += 1
|
226
|
+
end
|
227
|
+
migration_name = "#{migration_test}#{migration_number}"
|
228
|
+
Rails::Generator::Base.instance('migration', [migration_name], {:command => :create, :generator => 'migration'}).command(:create).invoke!
|
229
|
+
if migration = Dir[File.join(migration_path, "*#{migration_name}.rb")].first
|
230
|
+
migration_up = []
|
231
|
+
migration_down = []
|
232
|
+
for table, columns in indices.sort{|a, b| a[0].to_s <=> b[0].to_s}
|
233
|
+
next if columns.empty?
|
234
|
+
migration_up << "\s\s\s\s# Indices for `#{table}`"
|
235
|
+
migration_down << "\s\s\s\s# Remove indices for `#{table}`"
|
236
|
+
for column in columns
|
237
|
+
migration_up << "\s\s\s\sadd_index :#{table}, #{column.inspect}"
|
238
|
+
migration_down << "\s\s\s\sremove_index :#{table}, #{column.inspect}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
migration_contents = File.read(migration).gsub("def self.up", "def self.up\n#{migration_up.join("\n")}").gsub("def self.down", "def self.down\n#{migration_down.join("\n")}")
|
242
|
+
File.open(migration, 'w+') do |file|
|
243
|
+
file.puts migration_contents
|
244
|
+
end
|
245
|
+
end
|
246
|
+
else
|
247
|
+
for table, columns in indices.sort{|a, b| a[0].to_s <=> b[0].to_s}
|
248
|
+
next if columns.empty?
|
249
|
+
puts "\s\s# Indices for `#{table}`"
|
250
|
+
for column in columns
|
251
|
+
if @perform_index
|
252
|
+
ActiveRecord::Migration.add_index(table, column)
|
253
|
+
else
|
254
|
+
puts "\s\sadd_index :#{table}, #{column.inspect}"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
puts ''
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'findex/tasks'
|
2
|
+
|
3
|
+
describe Findex do
|
4
|
+
describe "indexes task" do
|
5
|
+
it "should exist" do
|
6
|
+
Rake::Task['db:indexes'].should_not be_nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should default to listing all missing indices"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should create an indexes:boolean task" do
|
13
|
+
Rake::Task['db:indexes:boolean'].should_not be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should create an indexes:datetime task" do
|
17
|
+
Rake::Task['db:indexes:datetime'].should_not be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should create an indexes:geo task" do
|
21
|
+
Rake::Task['db:indexes:geo'].should_not be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should create an indexes:help task" do
|
25
|
+
Rake::Task['db:indexes:help'].should_not be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should create an indexes:migration task" do
|
29
|
+
Rake::Task['db:indexes:migration'].should_not be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should create an indexes:names task" do
|
33
|
+
Rake::Task['db:indexes:names'].should_not be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create an indexes:perform task" do
|
37
|
+
Rake::Task['db:indexes:perform'].should_not be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should create an indexes:primary task" do
|
41
|
+
Rake::Task['db:indexes:primary'].should_not be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should create an indexes:relationships task" do
|
45
|
+
Rake::Task['db:indexes:relationships'].should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create an indexes:types task" do
|
49
|
+
Rake::Task['db:indexes:types'].should_not be_nil
|
50
|
+
end
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: findex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Flip Sasser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-12 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: ""
|
17
|
+
email: flip@x451.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README.markdown
|
27
|
+
- Rakefile
|
28
|
+
- VERSION
|
29
|
+
- findex.gemspec
|
30
|
+
- lib/findex/tasks.rb
|
31
|
+
- spec/findex_tasks_spec.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/flipsasser/findex
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Rake tasks to check your Rails models for missing indexes
|
60
|
+
test_files:
|
61
|
+
- spec/findex_tasks_spec.rb
|