sequel_core 1.4.0 → 1.5.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.
Files changed (51) hide show
  1. data/CHANGELOG +74 -0
  2. data/COPYING +1 -0
  3. data/README +17 -6
  4. data/Rakefile +16 -21
  5. data/lib/sequel_core.rb +18 -28
  6. data/lib/sequel_core/adapters/ado.rb +3 -15
  7. data/lib/sequel_core/adapters/dbi.rb +1 -14
  8. data/lib/sequel_core/adapters/informix.rb +3 -3
  9. data/lib/sequel_core/adapters/jdbc.rb +2 -2
  10. data/lib/sequel_core/adapters/mysql.rb +39 -59
  11. data/lib/sequel_core/adapters/odbc.rb +18 -38
  12. data/lib/sequel_core/adapters/openbase.rb +1 -17
  13. data/lib/sequel_core/adapters/oracle.rb +1 -19
  14. data/lib/sequel_core/adapters/postgres.rb +20 -60
  15. data/lib/sequel_core/adapters/sqlite.rb +4 -8
  16. data/lib/sequel_core/connection_pool.rb +150 -0
  17. data/lib/sequel_core/core_ext.rb +41 -0
  18. data/lib/sequel_core/core_sql.rb +35 -38
  19. data/lib/sequel_core/database.rb +20 -17
  20. data/lib/sequel_core/dataset.rb +49 -80
  21. data/lib/sequel_core/dataset/callback.rb +11 -13
  22. data/lib/sequel_core/dataset/convenience.rb +18 -136
  23. data/lib/sequel_core/dataset/pagination.rb +81 -0
  24. data/lib/sequel_core/dataset/sequelizer.rb +5 -4
  25. data/lib/sequel_core/dataset/sql.rb +43 -33
  26. data/lib/sequel_core/deprecated.rb +200 -0
  27. data/lib/sequel_core/exceptions.rb +0 -14
  28. data/lib/sequel_core/object_graph.rb +199 -0
  29. data/lib/sequel_core/pretty_table.rb +27 -24
  30. data/lib/sequel_core/schema/generator.rb +16 -4
  31. data/lib/sequel_core/schema/sql.rb +5 -3
  32. data/lib/sequel_core/worker.rb +1 -1
  33. data/spec/adapters/informix_spec.rb +1 -47
  34. data/spec/adapters/mysql_spec.rb +85 -54
  35. data/spec/adapters/oracle_spec.rb +1 -57
  36. data/spec/adapters/postgres_spec.rb +66 -49
  37. data/spec/adapters/sqlite_spec.rb +4 -29
  38. data/spec/connection_pool_spec.rb +358 -0
  39. data/spec/core_sql_spec.rb +24 -19
  40. data/spec/database_spec.rb +13 -9
  41. data/spec/dataset_spec.rb +59 -78
  42. data/spec/object_graph_spec.rb +202 -0
  43. data/spec/pretty_table_spec.rb +1 -9
  44. data/spec/schema_generator_spec.rb +7 -1
  45. data/spec/schema_spec.rb +27 -0
  46. data/spec/sequelizer_spec.rb +2 -2
  47. data/spec/spec_helper.rb +4 -2
  48. metadata +16 -57
  49. data/lib/sequel_core/array_keys.rb +0 -322
  50. data/lib/sequel_core/model.rb +0 -8
  51. data/spec/array_keys_spec.rb +0 -682
@@ -0,0 +1,200 @@
1
+ module Sequel
2
+ # This module makes it easy to add deprecation functionality to other classes.
3
+ module Deprecation
4
+ # This sets the output stream for the deprecation messages. Set it to an IO
5
+ # (or any object that responds to puts) and it will call puts on that
6
+ # object with the deprecation message. Set to nil to ignore deprecation messages.
7
+ def self.deprecation_message_stream=(file)
8
+ @dms = file
9
+ end
10
+
11
+ # Set this to true to print tracebacks with every deprecation message,
12
+ # so you can see exactly where in your code the deprecated methods are
13
+ # being called.
14
+ def self.print_tracebacks=(pt)
15
+ @pt = pt
16
+ end
17
+
18
+ # Puts the messages unaltered to the deprecation message stream
19
+ def self.deprecate(message)
20
+ if @dms
21
+ @dms.puts(message)
22
+ caller.each{|c| @dms.puts(c)} if @pt
23
+ end
24
+ end
25
+
26
+ # Formats the message with a message that it will be removed in Sequel 2.0.
27
+ # This is the method that is added to the classes that include Sequel::Deprecation.
28
+ def deprecate(meth, message = nil)
29
+ ::Sequel::Deprecation.deprecate("#{meth} is deprecated, and will be removed in Sequel 2.0.#{" #{message}." if message}")
30
+ end
31
+ end
32
+
33
+ class << self
34
+ include Sequel::Deprecation
35
+ def method_missing(m, *args) #:nodoc:
36
+ deprecate("Sequel.method_missing", "You should define Sequel.#{m} for the adapter.")
37
+ c = Database.adapter_class(m)
38
+ begin
39
+ # three ways to invoke this:
40
+ # 0 arguments: Sequel.dbi
41
+ # 1 argument: Sequel.dbi(db_name)
42
+ # more args: Sequel.dbi(db_name, opts)
43
+ case args.size
44
+ when 0
45
+ opts = {}
46
+ when 1
47
+ opts = args[0].is_a?(Hash) ? args[0] : {:database => args[0]}
48
+ else
49
+ opts = args[1].merge(:database => args[0])
50
+ end
51
+ rescue
52
+ raise Error::AdapterNotFound, "Unknown adapter (#{m})"
53
+ end
54
+ c.new(opts)
55
+ end
56
+ end
57
+
58
+ class Dataset
59
+ include Deprecation
60
+
61
+ MUTATION_RE = /^(.+)!$/.freeze
62
+
63
+ def clone_merge(opts = {}) #:nodoc:
64
+ deprecate("Sequel::Dataset#clone", "Use clone")
65
+ clone(opts)
66
+ end
67
+
68
+ def set_options(opts) #:nodoc:
69
+ deprecate("Sequel::Dataset#set_options")
70
+ @opts = opts
71
+ @columns = nil
72
+ end
73
+
74
+ def set_row_proc(&filter) #:nodoc:
75
+ deprecate("Sequel::Dataset#set_row_proc", "Use row_proc=")
76
+ @row_proc = filter
77
+ end
78
+
79
+ def remove_row_proc #:nodoc:
80
+ deprecate("Sequel::Dataset#remove_row_proc", "Use row_proc=nil")
81
+ @row_proc = nil
82
+ end
83
+
84
+ # Provides support for mutation methods (filter!, order!, etc.) and magic
85
+ # methods.
86
+ def method_missing(m, *args, &block) #:nodoc:
87
+ if m.to_s =~ MUTATION_RE
88
+ meth = $1.to_sym
89
+ super unless respond_to?(meth)
90
+ copy = send(meth, *args, &block)
91
+ super if copy.class != self.class
92
+ deprecate("Sequel::Dataset#method_missing", "Define Sequel::Dataset##{m}, or use Sequel::Dataset.def_mutation_method(:#{meth})")
93
+ @opts.merge!(copy.opts)
94
+ self
95
+ elsif magic_method_missing(m)
96
+ send(m, *args)
97
+ else
98
+ super
99
+ end
100
+ end
101
+
102
+ MAGIC_METHODS = {
103
+ /^order_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}) or define order_by_#{c}"); order(c)}},
104
+ /^first_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}).first or define first_by_#{c}"); order(c).first}},
105
+ /^last_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}).last or define last_by_#{c}"); order(c).last}},
106
+ /^filter_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}) or define filter_by_#{c}"); filter(c => v)}},
107
+ /^all_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}).all or define all_by_#{c}"); filter(c => v).all}},
108
+ /^find_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}).first or define find_by_#{c}"); filter(c => v).first}},
109
+ /^group_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use group(#{c.inspect}) or define group_by_#{c}"); group(c)}},
110
+ /^count_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use group_and_count(#{c.inspect}) or define count_by_#{c})"); group_and_count(c)}}
111
+ }
112
+
113
+ # Checks if the given method name represents a magic method and
114
+ # defines it. Otherwise, nil is returned.
115
+ def magic_method_missing(m) #:nodoc:
116
+ method_name = m.to_s
117
+ MAGIC_METHODS.each_pair do |r, p|
118
+ if method_name =~ r
119
+ impl = p[$1.to_sym]
120
+ return Dataset.class_def(m, &impl)
121
+ end
122
+ end
123
+ nil
124
+ end
125
+ end
126
+
127
+ module SQL
128
+ module DeprecatedColumnMethods #:nodoc:
129
+ AS = 'AS'.freeze
130
+ DESC = 'DESC'.freeze
131
+ ASC = 'ASC'.freeze
132
+
133
+ def as(a) #:nodoc:
134
+ Sequel::Deprecation.deprecate("Object#as is deprecated and will be removed in Sequel 2.0. Use Symbol#as or String#as.")
135
+ ColumnExpr.new(self, AS, a)
136
+ end
137
+ def AS(a) #:nodoc:
138
+ Sequel::Deprecation.deprecate("Object#AS is deprecated and will be removed in Sequel 2.0. Use Symbol#as or String#as.")
139
+ ColumnExpr.new(self, AS, a)
140
+ end
141
+ def desc #:nodoc:
142
+ Sequel::Deprecation.deprecate("Object#desc is deprecated and will be removed in Sequel 2.0. Use Symbol#desc or String#desc.")
143
+ ColumnExpr.new(self, DESC)
144
+ end
145
+ def DESC #:nodoc:
146
+ Sequel::Deprecation.deprecate("Object#DESC is deprecated and will be removed in Sequel 2.0. Use Symbol#desc or String#desc.")
147
+ ColumnExpr.new(self, DESC)
148
+ end
149
+ def asc #:nodoc:
150
+ Sequel::Deprecation.deprecate("Object#asc is deprecated and will be removed in Sequel 2.0. Use Symbol#asc or String#asc.")
151
+ ColumnExpr.new(self, ASC)
152
+ end
153
+ def ASC #:nodoc:
154
+ Sequel::Deprecation.deprecate("Object#ASC is deprecated and will be removed in Sequel 2.0. Use Symbol#asc or String#asc.")
155
+ ColumnExpr.new(self, ASC)
156
+ end
157
+ def all #:nodoc:
158
+ Sequel::Deprecation.deprecate("Object#all is deprecated and will be removed in Sequel 2.0. Use :#{self}.* or '#{self}.*'.lit.")
159
+ Sequel::SQL::ColumnAll.new(self)
160
+ end
161
+ def ALL #:nodoc:
162
+ Sequel::Deprecation.deprecate("Object#ALL is deprecated and will be removed in Sequel 2.0. Use :#{self}.* or '#{self}.*'.lit.")
163
+ Sequel::SQL::ColumnAll.new(self)
164
+ end
165
+
166
+ def cast_as(t) #:nodoc:
167
+ Sequel::Deprecation.deprecate("Object#cast_as is deprecated and will be removed in Sequel 2.0. Use Symbol#cast_as or String#cast_as.")
168
+ if t.is_a?(Symbol)
169
+ t = t.to_s.lit
170
+ end
171
+ Sequel::SQL::Function.new(:cast, self.as(t))
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ class Object
178
+ include Sequel::SQL::DeprecatedColumnMethods
179
+ def Sequel(*args) #:nodoc:
180
+ Sequel::Deprecation.deprecate("Object#Sequel is deprecated and will be removed in Sequel 2.0. Use Sequel.connect.")
181
+ Sequel.connect(*args)
182
+ end
183
+ def rollback! #:nodoc:
184
+ Sequel::Deprecation.deprecate("Object#rollback! is deprecated and will be removed in Sequel 2.0. Use raise Sequel::Error::Rollback.")
185
+ raise Sequel::Error::Rollback
186
+ end
187
+ end
188
+
189
+ class Symbol
190
+ # Converts missing method calls into functions on columns, if the
191
+ # method name is made of all upper case letters.
192
+ def method_missing(sym, *args) #:nodoc:
193
+ if ((s = sym.to_s) =~ /^([A-Z]+)$/)
194
+ Sequel::Deprecation.deprecate("Symbol#method_missing is deprecated and will be removed in Sequel 2.0. Use :#{sym}[:#{self}].")
195
+ Sequel::SQL::Function.new(s.downcase, self)
196
+ else
197
+ super
198
+ end
199
+ end
200
+ end
@@ -35,17 +35,3 @@ module Sequel
35
35
  class AdapterNotFound < Error ; end
36
36
  end
37
37
  end
38
-
39
- # Object extensions
40
- class Object
41
- # Cancels the current transaction without an error:
42
- #
43
- # DB.tranaction do
44
- # ...
45
- # rollback! if failed_to_contact_client
46
- # ...
47
- # end
48
- def rollback!
49
- raise Sequel::Error::Rollback
50
- end
51
- end
@@ -0,0 +1,199 @@
1
+ module Sequel
2
+ class Dataset
3
+ # Allows you to join multiple datasets/tables and have the result set
4
+ # split into component tables.
5
+ #
6
+ # This differs from the usual usage of join, which returns the result set
7
+ # as a single hash. For example:
8
+ #
9
+ # # CREATE TABLE artists (id INTEGER, name TEXT);
10
+ # # CREATE TABLE albums (id INTEGER, name TEXT, artist_id INTEGER);
11
+ # DB[:artists].left_outer_join(:albums, :artist_id=>:id).first
12
+ # => {:id=>(albums.id||artists.id), :name=>(albums.name||artist.names), :artist_id=>albums.artist_id}
13
+ # DB[:artists].graph(:albums, :artist_id=>:id).first
14
+ # => {:artists=>{:id=>artists.id, :name=>artists.name}, :albums=>{:id=>albums.id, :name=>albums.name, :artist_id=>albums.artist_id}}
15
+ #
16
+ # Using a join such as left_outer_join, the attribute names that are shared between
17
+ # the tables are combined in the single return hash. You can get around that by
18
+ # using .select with correct aliases for all of the columns, but it is simpler to
19
+ # use graph and have the result set split for you. In addition, graph respects
20
+ # any row_proc or transform attributes of the current dataset and the datasets
21
+ # you use with graph.
22
+ #
23
+ # Arguments:
24
+ # * dataset - Can be a symbol (specifying a table), another dataset,
25
+ # or an object that responds to .dataset and yields a symbol or a dataset
26
+ # * join_conditions - A conditions hash that is passed to the join_table method
27
+ # * options - A hash of graph options. The following options are currently used:
28
+ # * :table_alias - The alias to use for the table. If not specified, doesn't
29
+ # alias the table. You will get an error if the the alias (or table) name is
30
+ # used more than once.
31
+ # * :join_type - The type of join to use (passed to join_table). Defaults to
32
+ # :left_outer.
33
+ # * :select - Whether to select the columns from the you are joining, and
34
+ # include them as a separate hash in the output. With this set to false,
35
+ # it is like simply joining the tables. This is designed to be used for
36
+ # many_to_many join tables, where the columns are just foreign keys to primary
37
+ # keys in other tables.
38
+ def graph(dataset, join_conditions, options = {})
39
+ # Allow the use of a model, dataset, or symbol as the first argument
40
+ # Find the table name/dataset based on the argument
41
+ dataset = dataset.dataset if dataset.respond_to?(:dataset)
42
+ case dataset
43
+ when Symbol
44
+ table = dataset
45
+ dataset = @db[dataset]
46
+ when ::Sequel::Dataset
47
+ table = dataset.first_source
48
+ else
49
+ raise Error, "The dataset argument should be a symbol, dataset, or model"
50
+ end
51
+
52
+ # Raise Sequel::Error with explanation that the table alias has been used
53
+ raise_alias_error = lambda do
54
+ raise(Error, "this #{options[:table_alias] ? 'alias' : 'table'} has already been been used, please specify " \
55
+ "#{options[:table_alias] ? 'a different alias' : 'an alias via the :table_alias option'}")
56
+ end
57
+
58
+ # Only allow table aliases that haven't been used
59
+ table_alias = options[:table_alias] || table
60
+ raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
61
+
62
+ # Join the table early in order to avoid cloning the dataset twice
63
+ ds = join_table(options[:join_type] || :left_outer, table == table_alias ? table : "#{table} #{table_alias}", join_conditions)
64
+ opts = ds.opts
65
+
66
+ # Whether to include the table in the result set
67
+ add_table = options[:select] == false ? false : true
68
+ # Whether to add the columns to the list of column aliases
69
+ add_columns = !ds.opts.include?(:graph_aliases)
70
+
71
+ # Setup the initial graph data structure if it doesn't exist
72
+ unless graph = opts[:graph]
73
+ master = ds.first_source
74
+ raise_alias_error.call if master == table_alias
75
+ # Master hash storing all .graph related information
76
+ graph = opts[:graph] = {}
77
+ # Associates column aliases back to tables and columns
78
+ column_aliases = graph[:column_aliases] = {}
79
+ # Associates table alias (the master is never aliased)
80
+ table_aliases = graph[:table_aliases] = {master=>self}
81
+ # Keep track of the alias numbers used
82
+ ca_num = graph[:column_alias_num] = {}
83
+ # All columns in the master table are never
84
+ # aliased, but are not included if set_graph_aliases
85
+ # has been used.
86
+ if add_columns
87
+ select = (opts[:select] ||= [])
88
+ columns.each do |column|
89
+ column_aliases[column] = [master, column]
90
+ select.push(:"#{master}__#{column}")
91
+ end
92
+ end
93
+ end
94
+
95
+ # Add the table alias to the list of aliases
96
+ # Even if it isn't been used in the result set,
97
+ # we add a key for it with a nil value so we can check if it
98
+ # is used more than once
99
+ table_aliases = graph[:table_aliases]
100
+ table_aliases[table_alias] = add_table ? dataset : nil
101
+
102
+ # Add the columns to the selection unless we are ignoring them
103
+ if add_table && add_columns
104
+ select = opts[:select]
105
+ column_aliases = graph[:column_aliases]
106
+ ca_num = graph[:column_alias_num]
107
+ # If the column hasn't been used yet, don't alias it.
108
+ # If it has been used, try table_column.
109
+ # If that has been used, try table_column_N
110
+ # using the next value of N that we know hasn't been
111
+ # used
112
+ dataset.columns.each do |column|
113
+ col_alias, c = if column_aliases[column]
114
+ tc = :"#{table_alias}_#{column}"
115
+ if column_aliases[tc]
116
+ if can = ca_num[tc]
117
+ ca_num[tc] += 1
118
+ tc = :"#{tc}_#{can}"
119
+ else
120
+ ca_num[tc] = 1
121
+ tc = :"#{tc}_0"
122
+ end
123
+ end
124
+ [tc, :"#{table_alias}__#{column}___#{tc}"]
125
+ else
126
+ [column, :"#{table_alias}__#{column}"]
127
+ end
128
+ column_aliases[col_alias] = [table_alias, column]
129
+ select.push(c)
130
+ end
131
+ end
132
+ ds
133
+ end
134
+
135
+ # This allows you to manually specify the graph aliases to use
136
+ # when using graph. You can use it to only select certain
137
+ # columns, and have those columns mapped to specific aliases
138
+ # in the result set. This is the equivalent of .select for a
139
+ # graphed dataset, and must be used instead of .select whenever
140
+ # graphing is used. Example:
141
+ #
142
+ # DB[:artists].graph(:albums, :artist_id=>:id).set_graph_aliases(:artist_name=>[:artists, :name], :album_name=>[:albums, :name]).first
143
+ # => {:artists=>{:name=>artists.name}, :albums=>{:name=>albums.name}}
144
+ #
145
+ # Arguments:
146
+ # * graph_aliases - Should be a hash with keys being symbols of
147
+ # column aliases, and values being arrays with two symbol elements.
148
+ # The first element of the array should be the table alias,
149
+ # and the second should be the actual column name.
150
+ def set_graph_aliases(graph_aliases)
151
+ ds = select(*graph_aliases.collect{|col_alias, tc| :"#{tc[0]}__#{tc[1]}#{"___#{col_alias}" unless tc[1] == col_alias}"})
152
+ ds.opts[:graph_aliases]=graph_aliases
153
+ ds
154
+ end
155
+
156
+ private
157
+ # Fetch the rows, split them into component table parts,
158
+ # tranform and run the row_proc on each part (if applicable),
159
+ # and yield a hash of the parts.
160
+ def graph_each(opts, &block)
161
+ # Reject tables with nil datasets, as they are excluded from
162
+ # the result set
163
+ datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
164
+ # Get just the list of table aliases into a local variable, for speed
165
+ table_aliases = datasets.collect{|ta,ds| ta}
166
+ # Get an array of arrays, one for each dataset, with
167
+ # the necessary information about each dataset, for speed
168
+ datasets = datasets.collect do |ta, ds|
169
+ [ta, ds, ds.instance_variable_get(:@transform), ds.row_proc]
170
+ end
171
+ # Use the manually set graph aliases, if any, otherwise
172
+ # use the ones automatically created by .graph
173
+ column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
174
+ fetch_rows(select_sql(opts)) do |r|
175
+ graph = {}
176
+ # Create the sub hashes, one per table
177
+ table_aliases.each{|ta| graph[ta]={}}
178
+ # Split the result set based on the column aliases
179
+ # If there are columns in the result set that are
180
+ # not in column_aliases, they are ignored
181
+ column_aliases.each do |col_alias, tc|
182
+ ta, column = tc
183
+ graph[ta][column] = r[col_alias]
184
+ end
185
+ # For each dataset, transform and run the row
186
+ # row_proc if applicable
187
+ datasets.each do |ta,ds,tr,rp|
188
+ g = graph[ta]
189
+ g = ds.transform_load(g) if tr
190
+ g = rp[g] if rp
191
+ graph[ta] = g
192
+ end
193
+
194
+ yield graph
195
+ end
196
+ self
197
+ end
198
+ end
199
+ end
@@ -1,13 +1,27 @@
1
1
  module Sequel
2
- # Prints nice-looking plain-text tables
3
- # +--+-------+
4
- # |id|name |
5
- # |--+-------|
6
- # |1 |fasdfas|
7
- # |2 |test |
8
- # +--+-------+
9
2
  module PrettyTable
10
- def self.records_columns(records)
3
+ # Prints nice-looking plain-text tables
4
+ #
5
+ # +--+-------+
6
+ # |id|name |
7
+ # |--+-------|
8
+ # |1 |fasdfas|
9
+ # |2 |test |
10
+ # +--+-------+
11
+ def self.print(records, columns = nil) # records is an array of hashes
12
+ columns ||= records_columns(records)
13
+ sizes = column_sizes(records, columns)
14
+
15
+ puts separator_line(columns, sizes)
16
+ puts header_line(columns, sizes)
17
+ puts separator_line(columns, sizes)
18
+ records.each {|r| puts data_line(columns, sizes, r)}
19
+ puts separator_line(columns, sizes)
20
+ end
21
+ end
22
+ class << PrettyTable
23
+ private
24
+ def records_columns(records)
11
25
  columns = []
12
26
  records.each do |r|
13
27
  if Array === r && (k = r.keys)
@@ -19,7 +33,7 @@ module Sequel
19
33
  columns
20
34
  end
21
35
 
22
- def self.column_sizes(records, columns)
36
+ def column_sizes(records, columns)
23
37
  sizes = Hash.new {0}
24
38
  columns.each do |c|
25
39
  s = c.to_s.size
@@ -34,12 +48,12 @@ module Sequel
34
48
  sizes
35
49
  end
36
50
 
37
- def self.separator_line(columns, sizes)
51
+ def separator_line(columns, sizes)
38
52
  l = ''
39
53
  '+' + columns.map {|c| '-' * sizes[c]}.join('+') + '+'
40
54
  end
41
55
 
42
- def self.format_cell(size, v)
56
+ def format_cell(size, v)
43
57
  case v
44
58
  when Bignum, Fixnum
45
59
  "%#{size}d" % v
@@ -50,24 +64,13 @@ module Sequel
50
64
  end
51
65
  end
52
66
 
53
- def self.data_line(columns, sizes, record)
67
+ def data_line(columns, sizes, record)
54
68
  '|' + columns.map {|c| format_cell(sizes[c], record[c])}.join('|') + '|'
55
69
  end
56
70
 
57
- def self.header_line(columns, sizes)
71
+ def header_line(columns, sizes)
58
72
  '|' + columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') + '|'
59
73
  end
60
-
61
- def self.print(records, columns = nil) # records is an array of hashes
62
- columns ||= records_columns(records)
63
- sizes = column_sizes(records, columns)
64
-
65
- puts separator_line(columns, sizes)
66
- puts header_line(columns, sizes)
67
- puts separator_line(columns, sizes)
68
- records.each {|r| puts data_line(columns, sizes, r)}
69
- puts separator_line(columns, sizes)
70
- end
71
74
  end
72
75
  end
73
76