sequel_core 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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