constantrecord 0.0.2 → 0.1.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/Rakefile +1 -1
- data/constantrecord.gemspec +2 -2
- data/lib/constantrecord.rb +338 -251
- data/test/constantrecord_test.rb +16 -1
- metadata +2 -2
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
|
|
3
3
|
require 'rake'
|
4
4
|
require 'echoe'
|
5
5
|
|
6
|
-
Echoe.new('constantrecord', '0.0
|
6
|
+
Echoe.new('constantrecord', '0.1.0') do |p|
|
7
7
|
p.description = "A tiny ActiveRecord substitute for small, never changing database tables."
|
8
8
|
p.url = "http://github.com/ChristophPetschnig/constantrecord"
|
9
9
|
p.author = "Christoph Petschnig"
|
data/constantrecord.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{constantrecord}
|
5
|
-
s.version = "0.0
|
5
|
+
s.version = "0.1.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Christoph Petschnig"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-05-07}
|
10
10
|
s.description = %q{A tiny ActiveRecord substitute for small, never changing database tables.}
|
11
11
|
s.email = %q{info@purevirtual.de}
|
12
12
|
s.extra_rdoc_files = ["lib/constantrecord.rb", "README.rdoc"]
|
data/lib/constantrecord.rb
CHANGED
@@ -1,252 +1,339 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2009 Christoph Petschnig
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
#++
|
23
|
-
|
24
|
-
module ConstantRecord
|
25
|
-
# ConstantRecord::Base is a tiny ActiveRecord substitute for small, never
|
26
|
-
# changing database tables.
|
27
|
-
#
|
28
|
-
# == Usage:
|
29
|
-
#
|
30
|
-
# class Currency < ConstantRecord::Base
|
31
|
-
# data 'EUR', 'USD', 'CAD', 'GBP', 'CHF'
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# or
|
35
|
-
#
|
36
|
-
# class MoreDetailedCurrency < ConstantRecord::Base
|
37
|
-
# columns :short, :description
|
38
|
-
# data ['EUR', 'Euro'],
|
39
|
-
# ['USD', 'US Dollar'],
|
40
|
-
# ['CAD', 'Canadian Dollar'],
|
41
|
-
# ['GBP', 'British Pound sterling'],
|
42
|
-
# ['CHF', 'Swiss franc']
|
43
|
-
# end
|
44
|
-
#
|
45
|
-
# To show all records in a HTML select field, use:
|
46
|
-
#
|
47
|
-
# <%= f.select :currency_id, Currency.options_for_select %>
|
48
|
-
#
|
49
|
-
class Base
|
50
|
-
|
51
|
-
private
|
52
|
-
attr_writer :id, :name
|
53
|
-
|
54
|
-
public
|
55
|
-
attr_reader :id, :name
|
56
|
-
|
57
|
-
# Set the column names of the constant table.
|
58
|
-
# Default is one column called `name`
|
59
|
-
def self.columns(*args)
|
60
|
-
# remove the default column name
|
61
|
-
undef_method :name
|
62
|
-
|
63
|
-
i = 0
|
64
|
-
col_ar = args.collect do |column|
|
65
|
-
raise TypeError.new("You can only pass Symbol or String object to #{self}::columns.") unless column.kind_of?(Symbol) || column.kind_of?(String)
|
66
|
-
|
67
|
-
class_eval do
|
68
|
-
private
|
69
|
-
attr_writer column
|
70
|
-
public
|
71
|
-
attr_reader column
|
72
|
-
end
|
73
|
-
|
74
|
-
i += 1
|
75
|
-
[column.to_sym, i - 1]
|
76
|
-
end.flatten
|
77
|
-
|
78
|
-
@columns = Hash[*col_ar]
|
79
|
-
end
|
80
|
-
|
81
|
-
# Set the data. Arguments must be an Array.
|
82
|
-
def self.data(*args)
|
83
|
-
@data = args.collect{|arg| arg.kind_of?(Array) ? arg : [arg]}
|
84
|
-
end
|
85
|
-
|
86
|
-
# Constructor
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
def initialize(id, *values)
|
91
|
-
@id = id
|
92
|
-
|
93
|
-
return if values.empty?
|
94
|
-
|
95
|
-
# set the instance variables
|
96
|
-
get_columns.each do |key, value|
|
97
|
-
instance_variable_set("@#{key}", values[value])
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Implement +find+. Warning: conditions are only supported with
|
102
|
-
def self.find(*args)
|
103
|
-
selector = args[0]
|
104
|
-
|
105
|
-
# find might get called on constant_record_id.nil? == true
|
106
|
-
return nil if selector.nil?
|
107
|
-
|
108
|
-
raise TypeError.new("#{self}.find failed!\nArguments
|
109
|
-
|
110
|
-
if selector == :first
|
111
|
-
conditions = args[1][:conditions]
|
112
|
-
|
113
|
-
raise TypeError.new("#{self}.find failed!\nArguments
|
114
|
-
|
115
|
-
compare_col_nr = get_columns[conditions.keys[0]]
|
116
|
-
raise "Unknown column :#{conditions.keys[0]}" unless compare_col_nr
|
117
|
-
|
118
|
-
@data.each_with_index do |datum, i|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
selector
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
#
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
#
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
#
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
#
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 Christoph Petschnig
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
module ConstantRecord #:nodoc:
|
25
|
+
# ConstantRecord::Base is a tiny ActiveRecord substitute for small, never
|
26
|
+
# changing database tables.
|
27
|
+
#
|
28
|
+
# == Usage:
|
29
|
+
#
|
30
|
+
# class Currency < ConstantRecord::Base
|
31
|
+
# data 'EUR', 'USD', 'CAD', 'GBP', 'CHF'
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# or
|
35
|
+
#
|
36
|
+
# class MoreDetailedCurrency < ConstantRecord::Base
|
37
|
+
# columns :short, :description
|
38
|
+
# data ['EUR', 'Euro'],
|
39
|
+
# ['USD', 'US Dollar'],
|
40
|
+
# ['CAD', 'Canadian Dollar'],
|
41
|
+
# ['GBP', 'British Pound sterling'],
|
42
|
+
# ['CHF', 'Swiss franc']
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# To show all records in a HTML select field, use:
|
46
|
+
#
|
47
|
+
# <%= f.select :currency_id, Currency.options_for_select %>
|
48
|
+
#
|
49
|
+
class Base
|
50
|
+
|
51
|
+
private
|
52
|
+
attr_writer :id, :name #:nodoc:
|
53
|
+
|
54
|
+
public
|
55
|
+
attr_reader :id, :name #:nodoc:
|
56
|
+
|
57
|
+
# Set the column names of the constant table.
|
58
|
+
# Default is one column called `name`
|
59
|
+
def self.columns(*args)
|
60
|
+
# remove the default column name
|
61
|
+
undef_method :name
|
62
|
+
|
63
|
+
i = 0
|
64
|
+
col_ar = args.collect do |column|
|
65
|
+
raise TypeError.new("You can only pass Symbol or String object to #{self}::columns.") unless column.kind_of?(Symbol) || column.kind_of?(String)
|
66
|
+
|
67
|
+
class_eval do
|
68
|
+
private
|
69
|
+
attr_writer column
|
70
|
+
public
|
71
|
+
attr_reader column
|
72
|
+
end
|
73
|
+
|
74
|
+
i += 1
|
75
|
+
[column.to_sym, i - 1]
|
76
|
+
end.flatten
|
77
|
+
|
78
|
+
@columns = Hash[*col_ar]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Set the data. Arguments must be an Array.
|
82
|
+
def self.data(*args)
|
83
|
+
@data = args.collect{|arg| arg.kind_of?(Array) ? arg : [arg]}
|
84
|
+
end
|
85
|
+
|
86
|
+
# Constructor. Call with the <tt>id</tt> plus a list of the values.
|
87
|
+
#
|
88
|
+
# MyConstantRecord.new(1, 'value of column #1', 2, 3.333)
|
89
|
+
#
|
90
|
+
def initialize(id, *values)
|
91
|
+
@id = id
|
92
|
+
|
93
|
+
return if values.empty?
|
94
|
+
|
95
|
+
# set the instance variables
|
96
|
+
get_columns.each do |key, value|
|
97
|
+
instance_variable_set("@#{key}", values[value])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Implement +find+. Warning: <tt>:conditions</tt> are only supported with <tt>:first</tt>!
|
102
|
+
def self.find(*args)
|
103
|
+
selector = args[0]
|
104
|
+
|
105
|
+
# find might get called on constant_record_id.nil? == true
|
106
|
+
return nil if selector.nil?
|
107
|
+
|
108
|
+
raise TypeError.new("#{self}.find failed!\nArguments: #{args.inspect}") unless selector.kind_of?(Symbol) || selector.kind_of?(Fixnum)
|
109
|
+
|
110
|
+
if selector == :first
|
111
|
+
conditions = args[1][:conditions]
|
112
|
+
|
113
|
+
raise TypeError.new("#{self}.find failed!\nArguments: #{args.inspect}") unless conditions.kind_of?(Hash) && conditions.size == 1
|
114
|
+
|
115
|
+
compare_col_nr = get_columns[conditions.keys[0]]
|
116
|
+
raise "Unknown column :#{conditions.keys[0]}" unless compare_col_nr
|
117
|
+
|
118
|
+
@data.each_with_index do |datum, i|
|
119
|
+
# some special handling to integers
|
120
|
+
cond_compare = if datum[compare_col_nr].kind_of?(Integer)
|
121
|
+
conditions.values[0].to_i
|
122
|
+
else
|
123
|
+
# leave anything else as it is
|
124
|
+
conditions.values[0]
|
125
|
+
end
|
126
|
+
return self.new(i + 1, *datum) if datum[compare_col_nr] == cond_compare
|
127
|
+
end
|
128
|
+
|
129
|
+
return nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# ignore conditions on :all
|
133
|
+
return find_all if selector == :all
|
134
|
+
|
135
|
+
# ignore conditions if id is given as the first argument
|
136
|
+
return find_by_id(selector) if selector.kind_of?(Fixnum)
|
137
|
+
|
138
|
+
raise "#{self}.find failed!\nArguments: #{args.inspect}"
|
139
|
+
end
|
140
|
+
|
141
|
+
# Implement +count+. Warning: <tt>:conditions</tt> are not supported!
|
142
|
+
def self.count(*args)
|
143
|
+
selector = args[0] || :all
|
144
|
+
raise TypeError.new("#{self}.count failed!\nArguments: #{args.inspect}") unless selector.kind_of?(Symbol)
|
145
|
+
|
146
|
+
# ignore conditions on :all
|
147
|
+
return @data.size if selector == :all
|
148
|
+
|
149
|
+
raise "#{self}.count failed!\nArguments: #{args.inspect}"
|
150
|
+
end
|
151
|
+
|
152
|
+
# A ConstantRecord will never be a new record
|
153
|
+
def new_record? #:nodoc:
|
154
|
+
false
|
155
|
+
end
|
156
|
+
|
157
|
+
# A ConstantRecord should never be empty
|
158
|
+
def empty? #:nodoc:
|
159
|
+
false
|
160
|
+
end
|
161
|
+
|
162
|
+
# Show output in the form of `SELECT * FROM tablename;`
|
163
|
+
def self.table
|
164
|
+
# get columns in the form of {0 => :id, 1 => :name, ...}
|
165
|
+
cols = {:id => 0}.merge(Hash[*(get_columns.collect{|col_name, index| [col_name, index + 1]}.flatten)]).invert.sort
|
166
|
+
|
167
|
+
# calculate the maximum width of each column
|
168
|
+
max_size = []
|
169
|
+
cols.each do |index, name|
|
170
|
+
woci = with_of_column(index)
|
171
|
+
max_size << (woci > name.to_s.length ? woci : name.to_s.length)
|
172
|
+
end
|
173
|
+
|
174
|
+
output = ''
|
175
|
+
# build table header
|
176
|
+
output += '+-' + max_size.collect{|o| '-' * o}.join('-+-') + "-+\n"
|
177
|
+
output += '| ' + cols.collect{|o| o[1].to_s.ljust(max_size[o[0]])}.join(' | ') + " |\n"
|
178
|
+
output += '+-' + max_size.collect{|o| '-' * o}.join('-+-') + "-+\n"
|
179
|
+
# build table data
|
180
|
+
@data.each_with_index do |row, row_number|
|
181
|
+
output += '| ' + (row_number + 1).to_s.ljust(max_size[0]) + ' | '
|
182
|
+
index = 0
|
183
|
+
output += row.collect{|o| index += 1; o.to_s.ljust(max_size[index])}.join(' | ') + " |\n"
|
184
|
+
end
|
185
|
+
output += '+-' + max_size.collect{|o| '-' * o}.join('-+-') + "-+\n"
|
186
|
+
end
|
187
|
+
|
188
|
+
# Keep this to spot problems in integration with ActiveRecord
|
189
|
+
def method_missing(symbol, *args) #:nodoc:
|
190
|
+
::RAILS_DEFAULT_LOGGER.debug "#{self.class}#method_missing(:#{symbol})" if defined?(::RAILS_DEFAULT_LOGGER) && !::RAILS_DEFAULT_LOGGER.nil?
|
191
|
+
super symbol, *args
|
192
|
+
end
|
193
|
+
|
194
|
+
# Keep this to spot problems in integration with ActiveRecord
|
195
|
+
def respond_to?(symbol) #:nodoc:
|
196
|
+
result = super(symbol)
|
197
|
+
::RAILS_DEFAULT_LOGGER.debug "#{self.class}#respond_to?(:#{symbol}) => #{result}" if !result && defined?(::RAILS_DEFAULT_LOGGER) && !::RAILS_DEFAULT_LOGGER.nil?
|
198
|
+
result
|
199
|
+
end
|
200
|
+
|
201
|
+
# Handle +find_by_xxx+ calls on the class
|
202
|
+
def self.method_missing(symbol, *args) #:nodoc:
|
203
|
+
if /^find_by_([_a-zA-Z]\w*)$/ =~ (symbol.to_s)
|
204
|
+
return find(:first, :conditions => {$1.to_sym => args[0]})
|
205
|
+
end
|
206
|
+
::RAILS_DEFAULT_LOGGER.debug "#{self}::method_missing(:#{symbol})" if defined?(::RAILS_DEFAULT_LOGGER) && !::RAILS_DEFAULT_LOGGER.nil?
|
207
|
+
super symbol, *args
|
208
|
+
end
|
209
|
+
|
210
|
+
# Keep this to spot problems in integration with ActiveRecord
|
211
|
+
def self.respond_to?(symbol) #:nodoc:
|
212
|
+
result = super symbol
|
213
|
+
::RAILS_DEFAULT_LOGGER.debug "#{self}::respond_to?(:#{symbol}) => #{result}" if !result && defined?(::RAILS_DEFAULT_LOGGER) && !::RAILS_DEFAULT_LOGGER.nil?
|
214
|
+
result
|
215
|
+
end
|
216
|
+
|
217
|
+
# Creates options for a select box in a form. The result is basically the same as
|
218
|
+
# the following code with ActiveRecord:
|
219
|
+
#
|
220
|
+
# MyActiveRecord.find(:all).collect{|obj| [obj.name, obj.id]}
|
221
|
+
#
|
222
|
+
# === Usage
|
223
|
+
#
|
224
|
+
# With the class:
|
225
|
+
#
|
226
|
+
# class Currency < ConstantRecord::Base
|
227
|
+
# columns :short, :description
|
228
|
+
# data ['EUR', 'Euro'],
|
229
|
+
# ['USD', 'US Dollar']
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# The following erb code:
|
233
|
+
#
|
234
|
+
# <%= f.select :currency_id, Currency.options_for_select %>
|
235
|
+
#
|
236
|
+
# Results to:
|
237
|
+
#
|
238
|
+
# <select id="invoice_currency_id" name="invoice[currency_id]">
|
239
|
+
# <option value="1">EUR</option>
|
240
|
+
# <option value="2">USD</option>
|
241
|
+
# </select>
|
242
|
+
#
|
243
|
+
# While:
|
244
|
+
#
|
245
|
+
# <%= f.select :currency_id, Currency.options_for_select(
|
246
|
+
# :display => Proc.new { |obj| "#{obj.short} (#{obj.description})" },
|
247
|
+
# :value => :short, :include_null => true,
|
248
|
+
# :null_text => 'Please choose one', :null_value => nil ) %>
|
249
|
+
#
|
250
|
+
# Results to:
|
251
|
+
#
|
252
|
+
# <select id="invoice_currency_id" name="invoice[currency_id]">
|
253
|
+
# <option value="">Please choose one</option>
|
254
|
+
# <option value="EUR">EUR (Euro)</option>
|
255
|
+
# <option value="USD">USD (US Dollar)</option>
|
256
|
+
# </select>
|
257
|
+
#
|
258
|
+
# === Options
|
259
|
+
#
|
260
|
+
# [:display]
|
261
|
+
# The attribute to call to display the text in the select box or a Proc object.
|
262
|
+
# [:value]
|
263
|
+
# The value to use for the option value. Default is the id of the record.
|
264
|
+
# [:include_null]
|
265
|
+
# Make an entry with the value 0 in the selectbox. Default is +false+.
|
266
|
+
# [:null_text]
|
267
|
+
# The text to show with on value 0. Default is '-'.
|
268
|
+
# [:null_value]
|
269
|
+
# The value of the null option. Default is 0.
|
270
|
+
def self.options_for_select(options = {})
|
271
|
+
display = options[:display] || get_columns.invert[0]
|
272
|
+
raise "#{self}.options_for_select: :display must be either Symbol or Proc." unless display.kind_of?(Symbol) ||display.kind_of?(Proc)
|
273
|
+
|
274
|
+
if display.kind_of?(Symbol)
|
275
|
+
display_col_nr = get_columns[display]
|
276
|
+
raise "Unknown column :#{display}" unless display_col_nr
|
277
|
+
end
|
278
|
+
|
279
|
+
value = options[:value] || :id
|
280
|
+
|
281
|
+
i = 0
|
282
|
+
result = @data.collect do |datum|
|
283
|
+
i += 1
|
284
|
+
obj = self.new(i, *datum)
|
285
|
+
option_show = display.kind_of?(Symbol) ? datum[display_col_nr] : display.call(obj)
|
286
|
+
option_value = value == :id ? i : obj.send(value)
|
287
|
+
|
288
|
+
[option_show, option_value]
|
289
|
+
end
|
290
|
+
|
291
|
+
if options[:include_null] == true
|
292
|
+
result.unshift [ options[:null_text] || '-', options.key?(:null_value) ? options[:null_value] : 0 ]
|
293
|
+
end
|
294
|
+
|
295
|
+
result
|
296
|
+
end
|
297
|
+
|
298
|
+
private
|
299
|
+
|
300
|
+
# Get the name of the columns or the default value
|
301
|
+
def self.get_columns
|
302
|
+
# if columns were not set, the default value is one column
|
303
|
+
# with the name of "name"
|
304
|
+
@columns || { :name => 0 }
|
305
|
+
end
|
306
|
+
|
307
|
+
def get_columns #:nodoc:
|
308
|
+
self.class.get_columns
|
309
|
+
end
|
310
|
+
|
311
|
+
# Implementation of +find+(:all)
|
312
|
+
def self.find_all #:nodoc:
|
313
|
+
i = 0
|
314
|
+
@data.collect do |datum|
|
315
|
+
i += 1
|
316
|
+
self.new(i, *datum)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Implementation of +find+(:id)
|
321
|
+
def self.find_by_id(id) #:nodoc:
|
322
|
+
# check for valid range of selector
|
323
|
+
return nil if id <= 0 || id > @data.size
|
324
|
+
|
325
|
+
self.new(id, *@data[id - 1])
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.with_of_column(index)
|
329
|
+
return @data.size.to_s.length if index == 0
|
330
|
+
result = 0
|
331
|
+
@data.each do |row|
|
332
|
+
size = row[index - 1].to_s.length
|
333
|
+
result = size if size > result
|
334
|
+
end
|
335
|
+
result
|
336
|
+
end
|
337
|
+
|
338
|
+
end
|
252
339
|
end
|
data/test/constantrecord_test.rb
CHANGED
@@ -19,6 +19,15 @@ class MultiColumnClass < ConstantRecord::Base
|
|
19
19
|
['CHF', 'Swiss franc']
|
20
20
|
end
|
21
21
|
|
22
|
+
# A table/class that makes no sense, but has integers and booleans
|
23
|
+
class MultiColumnClassNotString < ConstantRecord::Base
|
24
|
+
columns :prime, :bool
|
25
|
+
data [11, false],
|
26
|
+
[13, false],
|
27
|
+
[17, true],
|
28
|
+
[19, false]
|
29
|
+
end
|
30
|
+
|
22
31
|
class TestConstantRecord < Test::Unit::TestCase
|
23
32
|
def test_simple_finder
|
24
33
|
assert_equal 'Estonia', SimpleClass.find(3).name
|
@@ -33,7 +42,7 @@ class TestConstantRecord < Test::Unit::TestCase
|
|
33
42
|
assert_equal [ 1, 2, 3 ], SimpleClass.find(:all).collect{|o| o.id}
|
34
43
|
assert_equal 3, SimpleClass.count
|
35
44
|
end
|
36
|
-
|
45
|
+
|
37
46
|
def test_simple_finder_with_custom_column_name
|
38
47
|
assert_equal 'Abbey Road', SimpleClass2.find(3).album
|
39
48
|
assert_equal 3, SimpleClass2.find(3).id
|
@@ -65,6 +74,12 @@ class TestConstantRecord < Test::Unit::TestCase
|
|
65
74
|
assert_equal 5, MultiColumnClass.count
|
66
75
|
end
|
67
76
|
|
77
|
+
def test_multi_column_not_string_finder
|
78
|
+
assert_equal 4, MultiColumnClassNotString.find_by_prime(19).id
|
79
|
+
assert_equal 4, MultiColumnClassNotString.find_by_prime('19').id
|
80
|
+
assert_equal 3, MultiColumnClassNotString.find_by_bool(true).id
|
81
|
+
end
|
82
|
+
|
68
83
|
def test_options_for_select
|
69
84
|
assert_equal [['Lithuania', 1], ['Latvia', 2], ['Estonia', 3]], SimpleClass.options_for_select
|
70
85
|
assert_equal [['n/a', 0], ['Lithuania', 1], ['Latvia', 2], ['Estonia', 3]],
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: constantrecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christoph Petschnig
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-07 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|