hgimenez-peegee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,54 @@
1
+ h1. What?
2
+
3
+ Peegee (pronounced "Pee - Gee", as in the letters PG, for Postgres) is a utility that provides an abstraction for performing PostgreSQL related tasks from Ruby, or your Rails application.
4
+
5
+ h1. Why?
6
+
7
+ This project started with the need to improve the performance of PostgreSQL's CLUSTER command. While clustering your database tables improves query performance significantly, the actual process of clustering takes unacceptable amounts of time. For instance, it may take roughly 20 hours on a moderately big set of tables (around 60GB). Your milage may vary, of course.
8
+ Refactoring the clustering functionality surfaced a clean set of utilities that resulted in the creation of this gem. Some are useful, and some are just pointless.
9
+
10
+ The initial code for this gem was created during the Boston.rb hackfest at Thoughtbot, on April 7th, 2009.
11
+
12
+ h1. Example usage
13
+
14
+ Assuming we're in a Rails app, you can simply do:
15
+
16
+ <pre><code>people_table = Peegee::Table.new(:table_name => 'people')
17
+ people_table.ddl # a string containing this table's DDL
18
+ people_table.indexes
19
+ people_table.foreign_keys
20
+ people_table.dependent_foreign_keys</code></pre>
21
+ The three commands above return arrays of Peegee::Index and Peegee::ForeignKey objects, which all respond to drop and create.
22
+ For example, you could drop and recreate the first dependent foreign key (some other table referencing people) with:
23
+ <pre><code>people_table.dependent_foreign_keys.first.drop
24
+ people_table.dependent_foreign_keys.first.create</code></pre>
25
+ After the call to drop, the @dependent_foreign_keys instance variable on the people_table object remains cached, and calling create will simply execute the cached SQL required to recreate the database object.
26
+
27
+ The strategy used for clustering a table is to store all dependencies in order to restore them later (as viewed above), and move all of the table's data on the order given by a certain index. This is all executed in a database transaction in case it blows up. The result should be just like the pgsql native CLUSTER command:
28
+ <pre><code>people_table.cluster('people_pk') #must specify an index by which to cluster</code></pre>
29
+
30
+ h2. Todo
31
+
32
+ The first order of business will be to create specs where applicable.
33
+
34
+ Then, the idea is to keep adding functionality that may be useful for DBAs or application developers and other PostgreSQL users. Some that come to mind are:
35
+
36
+ * Ability to clean out all of table's index and foreign key names, following a given pattern. On occasions, table names are altered leaving behind pesky legacy names for related objects.
37
+ * Ability to identify database stinks. For instance:
38
+ ** tables without primary keys, or indexes (which are not pure join tables)
39
+ ** foreign keys without indexes (useful for manually identifying and fixing if applicable),
40
+ ** report on columns that look like foreign keys, but aren't (based on rails conventions).
41
+ ** columns that are nullable, and are flagged as unique
42
+ ** tables with incrementing columns names, indiciating a possible denormalization
43
+ ** columns with a default value of 'NULL' (the varchar), where NULL may have been intended.
44
+ (much of these are stolen from the excellent "SchemaSpy":http://schemaspy.sourceforge.net/)
45
+
46
+ There's also a bunch of #TODO tags in the code, where there's clearly room for improvement.
47
+
48
+ I would also like to make this code ORM agnostic. Right now, it depends on ActiveRecord to retrieve a connection and execute commands.
49
+
50
+ Please fork away and help improve it.
51
+
52
+ h1. License
53
+
54
+ Copyright (c) 2009 Harold A. Gimenez, released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "peegee"
8
+ gem.summary = %Q{A set of utilities for doing PostgreSQL database related stuffs from ruby.}
9
+ gem.email = "harold.gimenez@gmail.com"
10
+ gem.homepage = "http://github.com/hgimenez/peegee"
11
+ gem.authors = ["Harold A. Gimenez"]
12
+ gem.add_dependency 'activerecord'
13
+ gem.requirements << 'A functioning PostgreSQL database, configured via ActiveRecord (for example, database.yml on a Rails project, or inline within your scripts).'
14
+
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+
34
+ task :default => :spec
35
+
36
+ require 'rake/rdoctask'
37
+ Rake::RDocTask.new do |rdoc|
38
+ if File.exist?('VERSION.yml')
39
+ config = YAML.load(File.read('VERSION.yml'))
40
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
41
+ else
42
+ version = ""
43
+ end
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "peegee #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
50
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -0,0 +1,118 @@
1
+ module Peegee
2
+ module Clustering
3
+
4
+ # Clusters this table. See http://www.postgresql.org/docs/8.3/interactive/sql-cluster.html
5
+ # Optionally specify the index to cluster by (by name or Peegee::Index object).
6
+ # If the index is not specify, it will try to induce which index to
7
+ # use by looking at postgresql's internals. If it can't find out,
8
+ # an exception will be raised.
9
+ def cluster(cluster_index = nil)
10
+ cluster_index = find_cluster_index(cluster_index)
11
+ puts "Cluster index is: #{cluster_index.inspect}"
12
+ puts "Cluster index type is: #{cluster_index.class.name}"
13
+ dependencies = remember_dependencies
14
+ ActiveRecord::Base.transaction do
15
+ puts "Clustering #{@table_name} by #{cluster_index.index_name} (with order => #{cluster_index.order})"
16
+ dependencies.map { |dep| dep.drop }
17
+ create_tmp_table
18
+ move_data(cluster_index)
19
+ drop_original_and_rename_tmp_table
20
+ dependencies.reverse.map { |dep| dep.create }
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # Retrieves the Peegee::Index object that will be used
27
+ # for clustering this table. The cluster_index parameter can
28
+ # be either a string representing the index name, or a Peegee::Index object.
29
+ # Raises an exception if either a proper index was not found
30
+ # or more than one index was found given a cluster_index name.
31
+ def find_cluster_index(cluster_index)
32
+ return cluster_index if cluster_index.kind_of?(Peegee::Index)
33
+ the_index = nil
34
+ if cluster_index #cluster_index is specified
35
+ the_index = indexes.select { |i| i.index_name == cluster_index}
36
+ else #find cluster index from postgresql's information schema
37
+ the_index = indexes.select { |i| i.is_clustered? }
38
+ end
39
+ raise "Ambiguous cluster_index definition. #{the_index.inspect}" if the_index.size != 1
40
+ the_index[0] #this is surely an array of size one.
41
+ end
42
+
43
+ # Creates the tmp table to be used to temporarily hold
44
+ # the data of the table being clustered. Additionally,
45
+ # it assigns the sequence of the table to the tmp table.
46
+ def create_tmp_table
47
+ ActiveRecord::Base.connection.execute(tmp_ddl)
48
+ reasign_sequence_to_tmp_table
49
+ end
50
+
51
+ # Moves the data contained in this table
52
+ # to a tmp table in the order specified by
53
+ # its cluster_index.
54
+ def move_data(cluster_index)
55
+ ActiveRecord::Base.connection.execute("insert into #{@table_name}_tmp select * from #{@table_name} order by #{cluster_index.order}")
56
+ end
57
+
58
+
59
+ # Returns the DDL for the tmp table where data is moved
60
+ # to temporarily during clustering.
61
+ def tmp_ddl
62
+ ddl.gsub(/\b#{@table_name}\b/, "#{@table_name}_tmp")
63
+ end
64
+
65
+ # Alters the sequence of the table being clustered,
66
+ # by assigning it to its temp table. This is necessary in order to
67
+ # drop the table being clustered (to clean out the dependency on
68
+ # the sequence).
69
+ # This method is called after having created the tmp table, otherwise it will fail.
70
+ #
71
+ # The method for finding a table's sequence is hackish.
72
+ # TODO: Find a better method for finding a table's sequence.
73
+ def reasign_sequence_to_tmp_table
74
+ sql = 'SELECT a.attname, ' +
75
+ 'pg_catalog.format_type(a.atttypid, a.atttypmod), ' +
76
+ '(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) ' +
77
+ ' FROM pg_catalog.pg_attrdef d ' +
78
+ ' WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), ' +
79
+ 'a.attnotnull, a.attnum ' +
80
+ 'FROM pg_catalog.pg_attribute a ' +
81
+ "WHERE a.attrelid = '#{oid}' AND a.attnum > 0 AND NOT a.attisdropped " +
82
+ " and " +
83
+ '(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) ' +
84
+ ' FROM pg_catalog.pg_attrdef d ' +
85
+ " WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) like '%nextval%' " +
86
+ 'ORDER BY a.attnum '
87
+ seq = ActiveRecord::Base.connection.execute(sql).entries.flatten
88
+ if !seq[0].nil? and !seq[2].empty?
89
+ seq[2].match /nextval\('[\"']{0,2}(\w*)[\"']{0,2}.*'::regclass\)/
90
+ sequence_name = $1 #the match above...
91
+ ActiveRecord::Base.connection.execute("ALTER SEQUENCE \"#{sequence_name}\" OWNED BY #{@table_name}_tmp.#{seq[0]}")
92
+ else
93
+ puts "\n\n\t*****#{@table_name} apparently doesn't have a sequence"
94
+ end
95
+ end
96
+
97
+
98
+ # Drops the table being clustered,
99
+ # and renames the tmp table to its original name.
100
+ def drop_original_and_rename_tmp_table
101
+ sql = []
102
+ sql << "drop table #{@table_name};"
103
+ sql << "alter table #{@table_name}_tmp rename to #{@table_name};"
104
+ sql.each do |s|
105
+ ActiveRecord::Base.connection.execute(s + ';')
106
+ end
107
+ end
108
+
109
+ # Retreives an array of this table's foreign keys,
110
+ # dependent foreign keys, and indexes.
111
+ def remember_dependencies
112
+ dependencies = []
113
+ dependencies << foreign_keys << dependent_foreign_keys << indexes
114
+ dependencies.flatten
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,28 @@
1
+ module Peegee
2
+ class Constraint
3
+
4
+ def initialize(opts = {})
5
+ @table_name = opts[:table_name]
6
+ @constraint_name = opts[:constraint_name]
7
+ @constraint_def = opts[:constraint_def]
8
+ end
9
+
10
+ # Returns human readable constraint.
11
+ def to_s
12
+ "Constraint: #{@constraint_name} on #{table_name}"
13
+ end
14
+
15
+ # Creates this constraint definition.
16
+ def create
17
+ sql = "alter table #{@table_name} add constraint #{@constraint_name} #{@constraint_def}"
18
+ ActiveRecord::Base.connection.execute(sql)
19
+ end
20
+
21
+ # Drops this constraint.
22
+ def drop
23
+ sql = "alter table #{@table_name} drop constraint #{@constraint_name}"
24
+ ActiveRecord::Base.connection.execute(sql)
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module Peegee
2
+ class ForeignKey < Peegee::Constraint
3
+
4
+ def initialize(opts)
5
+ super(opts)
6
+ end
7
+
8
+ # Returns the name of this foreign key.
9
+ def foreign_key_name
10
+ @constraint_name
11
+ end
12
+
13
+ # Returns human readable foreign key definition
14
+ def to_s
15
+ "Foreign Key: #{foreign_key_name} on #{table_name}"
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,72 @@
1
+ module Peegee
2
+ class Index
3
+
4
+ attr_accessor :index_name
5
+
6
+ def initialize(opts = {})
7
+ @table_name = opts[:table_name]
8
+ @index_name = opts[:index_name]
9
+ @clustered = opts[:clustered]
10
+ @def = opts[:def]
11
+ end
12
+
13
+ # prints human readable index definition
14
+ def to_s
15
+ "Index: #{@index_name} on #{@table_name} => (#{columns})"
16
+ end
17
+
18
+ # Returns the columns affected by this index
19
+ # TODO: Find out if there's a better way to
20
+ # retreive the column list, via postgres internals.
21
+ #
22
+ # TODO: Find out if this is the cleanest way to get
23
+ # the match of the regex
24
+ def columns
25
+ raise "Can't find index order for #{@index_name}" unless @def.match /\((.*)\)/
26
+ $1 #return the regex match (column list)
27
+ end
28
+
29
+ alias_method :order, :columns
30
+
31
+ # Drops this index
32
+ def drop
33
+ ActiveRecord::Base.connection.execute(drop_statement)
34
+ end
35
+
36
+ # Constructs the SQL statement to drop this index
37
+ # Optionally, pass in the boolean cascade value to
38
+ # also drop any dependent DB objects.
39
+ #
40
+ # PostgreSQL will error out if the index does not exists
41
+ # We purposely do not work around that.
42
+ def drop_statement(cascade = false)
43
+ drop_statement = "DROP INDEX \"#{@index_name}\""
44
+ drop_statement += " CASCADE" if cascade
45
+ drop_statement
46
+ end
47
+
48
+ # Creates this index
49
+ def create
50
+ ActiveRecord::Base.connection.execute(@def)
51
+ end
52
+
53
+ # returns true if this was the last clustered index
54
+ # on the associated table
55
+ def is_clustered?
56
+ @clustered
57
+ end
58
+
59
+ # Builds and returns Index object, given the index name
60
+ # The optional table_name is required when
61
+ # the index_name is not unique, ie: More than one
62
+ # index with that name was found on PostgreSQL's
63
+ # information catalog.
64
+ # If more than one index by that name is found,
65
+ # and table_name is not specified, an exception is raised.
66
+ # TODO: write implementation of this method...
67
+ def self.build(index_name, table_name = nil)
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module Peegee
2
+ class PrimaryKey < Peegee::Constraint
3
+
4
+ def initialize(opts)
5
+ super(opts)
6
+ end
7
+
8
+ # Returns the name of this primary key.
9
+ def primary_key_name
10
+ @constraint_name
11
+ end
12
+
13
+ # Returns human readable primary key definition
14
+ def to_s
15
+ "Primary Key: #{primary_key_name} on #{@table_name}"
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,168 @@
1
+ require File.dirname(__FILE__) + '/clustering'
2
+ module Peegee
3
+
4
+ class Table
5
+ include Peegee::Clustering
6
+
7
+ def initialize(opts = {})
8
+ @table_name = opts[:table_name]
9
+ end
10
+
11
+ def oid
12
+ @oid ||= fetch_oid
13
+ end
14
+
15
+ def foreign_keys
16
+ @foreign_keys ||= fetch_foreign_keys
17
+ end
18
+
19
+ def dependent_foreign_keys
20
+ @dependent_foreign_keys ||= fetch_dependent_foreign_keys
21
+ end
22
+
23
+ def primary_keys
24
+ @primary_keys ||= fetch_primary_keys
25
+ end
26
+
27
+ def unique_constraints
28
+ @unique_constraints ||= fetch_unique_constraints
29
+ end
30
+
31
+ def indexes
32
+ @indexes ||= fetch_indexes
33
+ end
34
+
35
+ # Returns the DDL for this table as a string.
36
+ def ddl
37
+ sql = 'SELECT a.attname, ' +
38
+ 'pg_catalog.format_type(a.atttypid, a.atttypmod), ' +
39
+ '(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) ' +
40
+ ' FROM pg_catalog.pg_attrdef d ' +
41
+ ' WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), ' +
42
+ 'a.attnotnull, a.attnum ' +
43
+ 'FROM pg_catalog.pg_attribute a ' +
44
+ "WHERE a.attrelid = '#{oid}' AND a.attnum > 0 AND NOT a.attisdropped " +
45
+ 'ORDER BY a.attnum '
46
+
47
+ column_defs = ActiveRecord::Base.connection.execute(sql).entries
48
+
49
+ ddl = "create table #{@table_name} ( "
50
+ columns = []
51
+ column_defs.each do |column_def|
52
+ #name and type
53
+ column = column_def[0] + ' ' + column_def[1] + ' '
54
+ #not null?
55
+ column += 'NOT NULL ' if column_def[3] == 't'
56
+ #add modifiers:
57
+ column += 'DEFAULT ' + column_def[2] unless (column_def[2].nil? || column_def[2].empty?)
58
+ columns << column
59
+ end
60
+
61
+ ddl += columns.join(', ') + ' )'
62
+ ddl.gsub('\\','')
63
+ end
64
+
65
+
66
+ private
67
+ def fetch_oid
68
+ sql = 'SELECT c.oid ' +
69
+ ' FROM pg_catalog.pg_class c ' +
70
+ ' LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace ' +
71
+ " WHERE c.relname ~ '^(#{@table_name})$' " +
72
+ ' AND pg_catalog.pg_table_is_visible(c.oid) '
73
+ return ActiveRecord::Base.connection.execute(sql).entries[0]
74
+ end
75
+
76
+
77
+
78
+ def fetch_primary_keys
79
+ sql = 'select conname ' +
80
+ ' , pg_get_constraintdef(pk.oid, true) as foreign_key ' +
81
+ ' from pg_catalog.pg_constraint pk ' +
82
+ ' inner join pg_class c ' +
83
+ ' on c.oid = pk.conrelid ' +
84
+ " where contype = 'p' " +
85
+ " and c.oid = '#{@table_name}'::regclass "
86
+ raw_pks = ActiveRecord::Base.connection.execute(sql).entries
87
+ return raw_pks.collect do |pk|
88
+ Peegee::ForeignKey.new(#TODO: Consider passing table object (self)
89
+ :table_name => @table_name,
90
+ :constraint_name => pk[0],
91
+ :constraint_def => pk[1])
92
+ end
93
+ end
94
+
95
+
96
+ def fetch_unique_constraints
97
+ sql = 'select conname ' +
98
+ ' , pg_get_constraintdef(uc.oid, true) as foreign_key ' +
99
+ ' from pg_catalog.pg_constraint uc ' +
100
+ ' inner join pg_class c ' +
101
+ ' on c.oid = uc.conrelid ' +
102
+ " where contype = 'u' " +
103
+ " and c.oid = '#{@table_name}'::regclass "
104
+ raw_ucs = ActiveRecord::Base.connection.execute(sql).entries
105
+ return raw_ucs.collect do |uc|
106
+ Peegee::UniqueConstraint.new(#TODO: Consider passing table object (self)
107
+ :table_name => @table_name,
108
+ :constraint_name => uc[0],
109
+ :constraint_def => uc[1])
110
+ end
111
+ end
112
+
113
+ def fetch_foreign_keys
114
+ sql = 'select conname ' +
115
+ ' , pg_get_constraintdef(fk.oid, true) as foreign_key ' +
116
+ ' from pg_catalog.pg_constraint fk ' +
117
+ ' inner join pg_class c ' +
118
+ ' on c.oid = fk.conrelid ' +
119
+ " where contype = 'f' " +
120
+ " and c.oid = '#{@table_name}'::regclass "
121
+ raw_fks = ActiveRecord::Base.connection.execute(sql).entries
122
+ return raw_fks.collect do |fk|
123
+ Peegee::ForeignKey.new(#TODO: Consider passing table object (self)
124
+ :table_name => @table_name,
125
+ :constraint_name => fk[0],
126
+ :constraint_def => fk[1])
127
+ end
128
+
129
+ end
130
+
131
+ def fetch_dependent_foreign_keys
132
+ sql = 'select pg_constraint.conname,' +
133
+ 'dep_table.relname, ' +
134
+ 'pg_get_constraintdef(pg_constraint.oid, true) ' +
135
+ 'from pg_constraint ' +
136
+ 'inner join pg_class dep_table on pg_constraint.conrelid = dep_table.oid ' +
137
+ "where pg_constraint.confrelid = '#{@table_name}'::regclass; "
138
+ raw_dpfks = ActiveRecord::Base.connection.execute(sql).entries
139
+ return raw_dpfks.collect do |dpfk|
140
+ Peegee::ForeignKey.new(#TODO: Consider passing table object (self)
141
+ :table_name => dpfk[1],
142
+ :constraint_name => dpfk[0],
143
+ :constraint_def => dpfk[2])
144
+ end
145
+ end
146
+
147
+ def fetch_indexes
148
+ sql = "SELECT pg_get_indexdef(i.indexrelid, 0, true) as index_definition " +
149
+ ", c2.relname as index_name " +
150
+ ", i.indisclustered " +
151
+ "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i " +
152
+ "WHERE c.oid = '#{@table_name}'::regclass AND c.oid = i.indrelid AND i.indexrelid = c2.oid " #+
153
+ #"AND i.indisprimary = false" #don't get primary key constraints...
154
+ #indexes = ActiveRecord::Base.connection.execute(sql).entries.collect{ |i| i[0] + ';'}
155
+ indexes = ActiveRecord::Base.connection.execute(sql).entries
156
+ return indexes.collect do |i|
157
+ Peegee::Index.new(:table_name => @table_name,
158
+ :index_name => i[1],
159
+ :clustered => (i[2] == 't' ? true : false),
160
+ :def => i[0])
161
+ end
162
+ end
163
+
164
+
165
+
166
+ end
167
+
168
+ end
@@ -0,0 +1,19 @@
1
+ module Peegee
2
+ class UniqueConstraint
3
+
4
+ def initialize(opts)
5
+ super(opts)
6
+ end
7
+
8
+ # Returns the name of this unique constraint
9
+ def unique_constraint_name
10
+ @constraint_name
11
+ end
12
+
13
+ #returns human readable unique constraint definition
14
+ def to_s
15
+ "Unique Constraint: #{unique_constraint_name} on #{table_name}"
16
+ end
17
+
18
+ end
19
+ end
data/lib/peegee.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'peegee/table'
2
+ require 'peegee/constraint'
3
+ require 'peegee/unique_constraint'
4
+ require 'peegee/primary_key'
5
+ require 'peegee/foreign_key'
6
+ require 'peegee/index'
data/peegee.gemspec ADDED
@@ -0,0 +1,54 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{peegee}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Harold A. Gimenez"]
9
+ s.date = %q{2009-04-10}
10
+ s.email = %q{harold.gimenez@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "README.textile"
13
+ ]
14
+ s.files = [
15
+ "README.textile",
16
+ "Rakefile",
17
+ "VERSION.yml",
18
+ "lib/peegee.rb",
19
+ "lib/peegee/clustering.rb",
20
+ "lib/peegee/constraint.rb",
21
+ "lib/peegee/foreign_key.rb",
22
+ "lib/peegee/index.rb",
23
+ "lib/peegee/primary_key.rb",
24
+ "lib/peegee/table.rb",
25
+ "lib/peegee/unique_constraint.rb",
26
+ "peegee.gemspec",
27
+ "spec/peegee_spec.rb",
28
+ "spec/spec_helper.rb"
29
+ ]
30
+ s.has_rdoc = true
31
+ s.homepage = %q{http://github.com/hgimenez/peegee}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.requirements = ["A functioning PostgreSQL database, configured via ActiveRecord (for example, database.yml on a Rails project, or inline within your scripts)."]
35
+ s.rubygems_version = %q{1.3.1}
36
+ s.summary = %q{A set of utilities for doing PostgreSQL database related stuffs from ruby.}
37
+ s.test_files = [
38
+ "spec/peegee_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 2
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<activerecord>, [">= 0"])
50
+ end
51
+ else
52
+ s.add_dependency(%q<activerecord>, [">= 0"])
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Peegee" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec'
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require 'peegee'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hgimenez-peegee
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Harold A. Gimenez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: harold.gimenez@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.textile
33
+ files:
34
+ - README.textile
35
+ - Rakefile
36
+ - VERSION.yml
37
+ - lib/peegee.rb
38
+ - lib/peegee/clustering.rb
39
+ - lib/peegee/constraint.rb
40
+ - lib/peegee/foreign_key.rb
41
+ - lib/peegee/index.rb
42
+ - lib/peegee/primary_key.rb
43
+ - lib/peegee/table.rb
44
+ - lib/peegee/unique_constraint.rb
45
+ - peegee.gemspec
46
+ - spec/peegee_spec.rb
47
+ - spec/spec_helper.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/hgimenez/peegee
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements:
68
+ - A functioning PostgreSQL database, configured via ActiveRecord (for example, database.yml on a Rails project, or inline within your scripts).
69
+ rubyforge_project:
70
+ rubygems_version: 1.2.0
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: A set of utilities for doing PostgreSQL database related stuffs from ruby.
74
+ test_files:
75
+ - spec/peegee_spec.rb
76
+ - spec/spec_helper.rb