glue 0.41.0 → 1.0.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/History.txt +6 -0
- data/Manifest.txt +6 -0
- data/README.txt +130 -0
- data/Rakefile +16 -0
- data/lib/glue.rb +49 -72
- data/test/test_glue.rb +218 -0
- metadata +84 -100
- data/doc/AUTHORS +0 -13
- data/doc/CHANGELOG.1 +0 -354
- data/doc/LICENSE +0 -32
- data/doc/RELEASES +0 -207
- data/lib/glue/attribute.rb +0 -113
- data/lib/glue/attributeutils.rb +0 -117
- data/lib/glue/autoreload.rb +0 -60
- data/lib/glue/builder.rb +0 -57
- data/lib/glue/builder/xml.rb +0 -103
- data/lib/glue/cache.rb +0 -22
- data/lib/glue/cache/drb.rb +0 -51
- data/lib/glue/cache/file.rb +0 -78
- data/lib/glue/cache/memcached.rb +0 -68
- data/lib/glue/cache/memory.rb +0 -79
- data/lib/glue/cache/og.rb +0 -61
- data/lib/glue/configuration.rb +0 -305
- data/lib/glue/fixture.rb +0 -154
- data/lib/glue/html.rb +0 -12
- data/lib/glue/localization.rb +0 -129
- data/lib/glue/logger.rb +0 -208
- data/lib/glue/mail.rb +0 -160
- data/lib/glue/mailer.rb +0 -55
- data/lib/glue/mailer/incoming.rb +0 -41
- data/lib/glue/mailer/outgoing.rb +0 -119
- data/lib/glue/settings.rb +0 -3
- data/lib/glue/uri.rb +0 -190
- data/lib/glue/validation.rb +0 -447
- data/lib/html/document.rb +0 -63
- data/lib/html/node.rb +0 -480
- data/lib/html/tokenizer.rb +0 -103
- data/lib/html/version.rb +0 -11
- data/test/fixture/article.csv +0 -3
- data/test/fixture/article.yml +0 -13
- data/test/fixture/user.yml +0 -12
- data/test/glue/builder/tc_xml.rb +0 -57
- data/test/glue/tc_aspects.rb +0 -99
- data/test/glue/tc_attribute.rb +0 -112
- data/test/glue/tc_attribute_mixins.rb +0 -86
- data/test/glue/tc_builder.rb +0 -30
- data/test/glue/tc_configuration.rb +0 -135
- data/test/glue/tc_fixture.rb +0 -98
- data/test/glue/tc_localization.rb +0 -49
- data/test/glue/tc_logger.rb +0 -43
- data/test/glue/tc_mail.rb +0 -99
- data/test/glue/tc_stores.rb +0 -16
- data/test/glue/tc_uri.rb +0 -97
- data/test/glue/tc_validation.rb +0 -217
- data/test/public/dummy_mailer/registration.xhtml +0 -5
data/lib/glue/cache/memory.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'facet/synchash'
|
2
|
-
|
3
|
-
require 'glue/cache'
|
4
|
-
|
5
|
-
module Glue
|
6
|
-
|
7
|
-
# A cache backed in memory.
|
8
|
-
#--
|
9
|
-
# This implementation is also the base for the Drb Cache.
|
10
|
-
#++
|
11
|
-
|
12
|
-
class MemoryCache < Cache
|
13
|
-
attr :hash
|
14
|
-
|
15
|
-
def initialize(options = {})
|
16
|
-
if options[:sync]
|
17
|
-
@hash = SyncHash
|
18
|
-
else
|
19
|
-
@hash = {}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# Get an object from the cache.
|
24
|
-
|
25
|
-
def get(key, options = nil)
|
26
|
-
@hash[key]
|
27
|
-
end
|
28
|
-
alias_method :read, :get
|
29
|
-
alias_method :[], :get
|
30
|
-
|
31
|
-
# Put an object in the cache.
|
32
|
-
|
33
|
-
def set(key, value = nil, options = nil)
|
34
|
-
@hash[key] = value
|
35
|
-
end
|
36
|
-
alias_method :put, :set
|
37
|
-
alias_method :write, :set
|
38
|
-
alias_method :[]=, :set
|
39
|
-
|
40
|
-
# Delete an object from the cache.
|
41
|
-
|
42
|
-
def delete(key, options = nil)
|
43
|
-
@hash.delete(key)
|
44
|
-
end
|
45
|
-
alias_method :remove, :delete
|
46
|
-
|
47
|
-
def delete_if(&block)
|
48
|
-
@hash.delete_if(&block)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Perform session garbage collection. Typically this method
|
52
|
-
# is called from a cron like mechanism.
|
53
|
-
|
54
|
-
def gc!
|
55
|
-
delete_if { |key, s| s.expired? }
|
56
|
-
end
|
57
|
-
|
58
|
-
# Return the mapping.
|
59
|
-
|
60
|
-
def mapping
|
61
|
-
@hash
|
62
|
-
end
|
63
|
-
|
64
|
-
# Return all keys in the cache.
|
65
|
-
|
66
|
-
def keys
|
67
|
-
@hash.keys
|
68
|
-
end
|
69
|
-
|
70
|
-
# Return all objects in the cache.
|
71
|
-
|
72
|
-
def all
|
73
|
-
@hash.values
|
74
|
-
end
|
75
|
-
alias_method :values, :all
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
data/lib/glue/cache/og.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'og'
|
2
|
-
require 'base64'
|
3
|
-
|
4
|
-
module Glue
|
5
|
-
|
6
|
-
class OgCached
|
7
|
-
include Og::EntityMixin
|
8
|
-
|
9
|
-
property :unique_id, String, :sql => 'PRIMARY KEY'
|
10
|
-
property :expires, Time
|
11
|
-
property :cache_name, String
|
12
|
-
property :content, String
|
13
|
-
|
14
|
-
set_primary_key :unique_id, String
|
15
|
-
end
|
16
|
-
|
17
|
-
class OgCache
|
18
|
-
|
19
|
-
def initialize(cache_name, keepalive = nil)
|
20
|
-
@cache_name = cache_name
|
21
|
-
@keepalive = keepalive
|
22
|
-
end
|
23
|
-
|
24
|
-
def []=(k,v)
|
25
|
-
unless s = OgCached.find_by_unique_id_and_cache_name(k.to_s, @cache_name)
|
26
|
-
s = OgCached.new
|
27
|
-
s.cache_name = @cache_name
|
28
|
-
s.expires = Time.now + @keepalive if @keepalive
|
29
|
-
s.unique_id = k.to_s
|
30
|
-
end
|
31
|
-
#s.content = v.to_yaml
|
32
|
-
s.content = encode(v)
|
33
|
-
s.insert
|
34
|
-
end
|
35
|
-
|
36
|
-
def [](k)
|
37
|
-
s = OgCached.find_by_unique_id_and_cache_name(k.to_s, @cache_name)
|
38
|
-
decode(s.content) if s
|
39
|
-
end
|
40
|
-
|
41
|
-
def gc!
|
42
|
-
OgCached.find(:condition => ["expires < ? AND cache_name = ?", Time.now, @cache_name]).each {|s| s.delete }
|
43
|
-
end
|
44
|
-
|
45
|
-
def all
|
46
|
-
OgCached.find_by_cache_name(@cache_name)
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def encode(c)
|
52
|
-
Base64.encode64(Marshal.dump(c))
|
53
|
-
end
|
54
|
-
|
55
|
-
def decode(c)
|
56
|
-
Marshal::load(Base64.decode64(c))
|
57
|
-
#s.content = YAML::load(s.content)
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
data/lib/glue/configuration.rb
DELETED
@@ -1,305 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
require 'facets/core/kernel/constant'
|
4
|
-
require 'facets/more/synchash'
|
5
|
-
require 'facets/more/dictionary'
|
6
|
-
require 'facets/core/string/capitalized'
|
7
|
-
require 'facets/core/class/cattr'
|
8
|
-
|
9
|
-
module Glue
|
10
|
-
|
11
|
-
# A Configuration holds a group of Settings organized by
|
12
|
-
# Owners. An owner is a class that represents the system to be
|
13
|
-
# configured. An alias for this class is Settings.
|
14
|
-
#
|
15
|
-
# You can pass strings, constants or symbols as keys for the
|
16
|
-
# classes to be configured. Passing symbols you can configure
|
17
|
-
# classes even before they are defined.
|
18
|
-
#--
|
19
|
-
# TODO: implement with annotations.
|
20
|
-
#++
|
21
|
-
|
22
|
-
class Configuration
|
23
|
-
|
24
|
-
# A hash of setting owners. Use double @'s to allow for
|
25
|
-
# the Settings alias.
|
26
|
-
#--
|
27
|
-
# TODO: find a better name.
|
28
|
-
#++
|
29
|
-
|
30
|
-
@@owners = SyncHash.new
|
31
|
-
|
32
|
-
# A datastructure to store Settings metadata.
|
33
|
-
#
|
34
|
-
# Please note the difference between :default and :value,
|
35
|
-
# :default does NOT override :value.
|
36
|
-
|
37
|
-
class Setting
|
38
|
-
attr_accessor :owner, :name, :type, :value, :options
|
39
|
-
|
40
|
-
def initialize(owner, name, options)
|
41
|
-
if options.key? :value
|
42
|
-
@value = options[:value]
|
43
|
-
elsif options.key? :default
|
44
|
-
@value = options[:default]
|
45
|
-
else
|
46
|
-
raise ArgumentError.new('A value is required')
|
47
|
-
end
|
48
|
-
|
49
|
-
@owner, @name = owner, name
|
50
|
-
@options = options
|
51
|
-
@type = options[:type] = options[:type] || @value.class
|
52
|
-
end
|
53
|
-
|
54
|
-
# Update the setting from an options hash. The update does
|
55
|
-
# NOT take default values into account!
|
56
|
-
|
57
|
-
def update(hash)
|
58
|
-
if hash.key? :value
|
59
|
-
@value = hash[:value]
|
60
|
-
@type = @value.class
|
61
|
-
end
|
62
|
-
|
63
|
-
if hash.key? :type
|
64
|
-
@type = hash[:type]
|
65
|
-
end
|
66
|
-
|
67
|
-
@options.update(hash)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Text representation of this setting.
|
71
|
-
|
72
|
-
def to_s
|
73
|
-
@value.to_s
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
# A collection of Settings. This helper enables intuitive
|
79
|
-
# settings initialization like this:
|
80
|
-
#
|
81
|
-
# Configuration.Compiler.template_root = 'public'
|
82
|
-
# instead of
|
83
|
-
# Configuration.setting :compiler, :template_root, :value => 'public'
|
84
|
-
|
85
|
-
class SettingCollection < Hash
|
86
|
-
attr_accessor :owner
|
87
|
-
|
88
|
-
# Handles setting readers and writers.
|
89
|
-
|
90
|
-
def method_missing(sym, *args)
|
91
|
-
if sym.to_s =~ /=$/
|
92
|
-
# Remove trailing
|
93
|
-
sym = sym.to_s.gsub(/=/, '').to_sym
|
94
|
-
Configuration.setting @owner, sym, :value => args.first
|
95
|
-
else
|
96
|
-
self[sym]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
class << self
|
102
|
-
|
103
|
-
# The configuration mode, typical modes include :debug,
|
104
|
-
# :stage, :live.
|
105
|
-
#
|
106
|
-
# [:debug]
|
107
|
-
# useful when debugging, extra debug information
|
108
|
-
# is emmited, actions, templates and shaders are
|
109
|
-
# reloaded, etc. The execution speed of the application
|
110
|
-
# is impaired.
|
111
|
-
#
|
112
|
-
# [:stage]
|
113
|
-
# test the application with live parameters
|
114
|
-
# (typically on a staging server).
|
115
|
-
#
|
116
|
-
# [:live]
|
117
|
-
# use the parameters for the live (production)
|
118
|
-
# server. Optimized for speed.
|
119
|
-
#
|
120
|
-
# Tries to set the default value from the NITRO_MODE
|
121
|
-
# environment variable.
|
122
|
-
|
123
|
-
attr_accessor :mode
|
124
|
-
|
125
|
-
def mode
|
126
|
-
mode = nil
|
127
|
-
if mode = ENV['CONFIGURATION_MODE']
|
128
|
-
$stderr.puts "CONFIGURATION_MODE is deprecated, use NITRO_MODE"
|
129
|
-
end
|
130
|
-
@mode || mode || ENV.fetch('NITRO_MODE', :debug).to_sym
|
131
|
-
end
|
132
|
-
|
133
|
-
# The log output destination.
|
134
|
-
#
|
135
|
-
# ['STDOUT' 'STDERR']
|
136
|
-
# Sets the log to stdout or stderr.
|
137
|
-
#
|
138
|
-
# [str]
|
139
|
-
# Any other string is regarded as path
|
140
|
-
|
141
|
-
attr_accessor :log
|
142
|
-
|
143
|
-
def log
|
144
|
-
return @log if @log
|
145
|
-
|
146
|
-
log = ENV.fetch('NITRO_LOG', Logger.new('log/app.log'))
|
147
|
-
|
148
|
-
if log.kind_of?(String)
|
149
|
-
if log =~ /(STD(?:OUT|ERR))/i
|
150
|
-
log = Object.const_get($1.upcase)
|
151
|
-
elsif File.directory?(File.dirname(log))
|
152
|
-
log = Logger.new(log)
|
153
|
-
else
|
154
|
-
log = 'log/app.log'
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
@log = log
|
159
|
-
end
|
160
|
-
|
161
|
-
alias kernel_load load
|
162
|
-
|
163
|
-
# Attempt to load external configuration in Ruby or
|
164
|
-
# YAML format. The files:
|
165
|
-
#
|
166
|
-
# * conf/mode.rb
|
167
|
-
# * conf/mode.yaml
|
168
|
-
#
|
169
|
-
# are considered.
|
170
|
-
|
171
|
-
def load(m = mode)
|
172
|
-
ruby_conf = "conf/#{m}.rb"
|
173
|
-
kernel_load(ruby_conf) if File.exist?(ruby_conf)
|
174
|
-
|
175
|
-
# Try to configure from a yaml file.
|
176
|
-
yml_conf = "conf/#{m}.yml"
|
177
|
-
Configuration.load_yaml(yml_conf) if File.exist?(yml_conf)
|
178
|
-
end
|
179
|
-
|
180
|
-
# Inject the configuration parameters provided as a hash
|
181
|
-
# (dictionary, ordered) to classes to be configured.
|
182
|
-
#
|
183
|
-
# === Warning: Pass an ordered hash (dictionary)
|
184
|
-
|
185
|
-
def setup(options)
|
186
|
-
options.each do |owner, ss|
|
187
|
-
next unless ss
|
188
|
-
ss.each do |name, s|
|
189
|
-
add_setting(owner, name.to_sym, :value => s)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
# Parse configuration parameters in yaml format.
|
195
|
-
|
196
|
-
def parse_yaml(options)
|
197
|
-
temp = YAML::load(options)
|
198
|
-
options = Dictionary.new
|
199
|
-
temp.each do |k, v|
|
200
|
-
options[k.gsub(/\./, '::').to_sym] = v
|
201
|
-
end
|
202
|
-
|
203
|
-
setup(options)
|
204
|
-
end
|
205
|
-
|
206
|
-
# Load an external ruby configuration file. Constant missing
|
207
|
-
# errors are not reported for extra flexibility.
|
208
|
-
|
209
|
-
def load_ruby(filename)
|
210
|
-
end
|
211
|
-
|
212
|
-
# Load and parse an external yaml configuration file.
|
213
|
-
|
214
|
-
def load_yaml(filename)
|
215
|
-
parse_yaml(File.read(filename))
|
216
|
-
end
|
217
|
-
|
218
|
-
# Manually add a configuration setting. The class key can
|
219
|
-
# be the actual class name constant or a symbol. If the
|
220
|
-
# setting is already defined it updates it.
|
221
|
-
#
|
222
|
-
# === Examples
|
223
|
-
#
|
224
|
-
# Configuration.add_setting Compiler, :verification, :value => 12, :doc => '...'
|
225
|
-
# Configuration.setting :IdPart, :verify_registration_email, :value => false
|
226
|
-
# s = Configuration.Compiler.verification.value
|
227
|
-
|
228
|
-
def add_setting(owner, name, options)
|
229
|
-
owner = owner.to_s.to_sym
|
230
|
-
@@owners[owner] ||= {}
|
231
|
-
if s = @@owners[owner][name]
|
232
|
-
# The setting already exists, update it.
|
233
|
-
s.update(options)
|
234
|
-
else
|
235
|
-
# The setting does not exist, create it.
|
236
|
-
@@owners[owner][name] = Setting.new(owner, name, options)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
alias_method :setting, :add_setting
|
240
|
-
|
241
|
-
# Return the settings for the given owner. The owner is
|
242
|
-
# typically the Class that represents the system to be
|
243
|
-
# configured. If no class is provided, it returns all the
|
244
|
-
# registered settings.
|
245
|
-
|
246
|
-
def settings(owner = nil)
|
247
|
-
if owner
|
248
|
-
owner = owner.to_s.to_sym
|
249
|
-
@@owners[owner]
|
250
|
-
else
|
251
|
-
@@owners.values.inject([]) { |memo, obj| memo.concat(obj.values) }
|
252
|
-
end
|
253
|
-
end
|
254
|
-
alias_method :all, :settings
|
255
|
-
alias_method :[], :settings
|
256
|
-
|
257
|
-
#--
|
258
|
-
# FIXME: this does not work as expected.
|
259
|
-
#++
|
260
|
-
|
261
|
-
def method_missing(sym)
|
262
|
-
if sym.to_s.capitalized?
|
263
|
-
bdl = SettingCollection.new
|
264
|
-
bdl.owner = sym
|
265
|
-
if hash = self[sym]
|
266
|
-
bdl.update(hash)
|
267
|
-
end
|
268
|
-
return bdl
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
end
|
274
|
-
|
275
|
-
# Alias for the Configuration class (shorter).
|
276
|
-
|
277
|
-
Settings = Configuration
|
278
|
-
|
279
|
-
end
|
280
|
-
|
281
|
-
class Module
|
282
|
-
|
283
|
-
# Defines a configuration setting for the enclosing class.
|
284
|
-
#
|
285
|
-
# === Example
|
286
|
-
#
|
287
|
-
# class Compiler
|
288
|
-
# setting :template_root, :default => 'src/template', :doc => 'The template root dir'
|
289
|
-
# end
|
290
|
-
|
291
|
-
def setting(sym, options = {})
|
292
|
-
Glue::Configuration.add_setting(self, sym, options)
|
293
|
-
|
294
|
-
module_eval %{
|
295
|
-
def self.#{sym}
|
296
|
-
Glue::Configuration[#{self}][:#{sym}].value
|
297
|
-
end
|
298
|
-
|
299
|
-
def self.#{sym}=(obj)
|
300
|
-
Glue::Configuration.setting #{self}, :#{sym}, :value => obj
|
301
|
-
end
|
302
|
-
}
|
303
|
-
end
|
304
|
-
|
305
|
-
end
|
data/lib/glue/fixture.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
require 'facet/kernel/constant'
|
2
|
-
|
3
|
-
require 'facet/ormsupport'
|
4
|
-
|
5
|
-
require 'glue/configuration'
|
6
|
-
require 'nitro/template'
|
7
|
-
|
8
|
-
module Glue
|
9
|
-
|
10
|
-
# A collection of helper methods.
|
11
|
-
|
12
|
-
class Fixtures
|
13
|
-
|
14
|
-
# The directory where the fixtures are located.
|
15
|
-
|
16
|
-
setting :root_dir, :default => 'test/fixture', :doc => 'The directory where the fixtures are located'
|
17
|
-
|
18
|
-
@fixtures = {}
|
19
|
-
|
20
|
-
class << self
|
21
|
-
|
22
|
-
def load(*classes)
|
23
|
-
for klass in classes
|
24
|
-
f = Fixture.new(klass).load
|
25
|
-
@fixtures[f.name] = f
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def [](klass)
|
30
|
-
@fixtures[klass]
|
31
|
-
end
|
32
|
-
|
33
|
-
def []=(klass, fixture)
|
34
|
-
@fixtures[klass] = fixture
|
35
|
-
end
|
36
|
-
|
37
|
-
def method_missing(sym)
|
38
|
-
if f = @fixtures[sym.to_s]
|
39
|
-
return f
|
40
|
-
end
|
41
|
-
super
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Fixtures is a fancy word for ‘sample data’. Fixtures allow you
|
47
|
-
# to populate your database with predefined data. Fixtures are
|
48
|
-
# typically used during testing or when providing initial data
|
49
|
-
# (bootstrap data) for a live application.
|
50
|
-
#
|
51
|
-
# A Fixture is a collection (Hash) of objects.
|
52
|
-
|
53
|
-
class Fixture < Hash
|
54
|
-
|
55
|
-
# The name of this Fixture.
|
56
|
-
|
57
|
-
attr_accessor :name
|
58
|
-
|
59
|
-
# The class that the Fixtures refer to.
|
60
|
-
|
61
|
-
attr_accessor :klass
|
62
|
-
|
63
|
-
# Used to keep the order.
|
64
|
-
|
65
|
-
attr_accessor :objects
|
66
|
-
|
67
|
-
def initialize(klass, options = { } )
|
68
|
-
@klass = klass
|
69
|
-
@name = class_to_name(klass)
|
70
|
-
@objects = []
|
71
|
-
load(options[:root_dir] || options[:root] || Fixtures.root_dir)
|
72
|
-
end
|
73
|
-
|
74
|
-
def load(root_dir = Fixtures.root_dir)
|
75
|
-
raise("The fixture root directory '#{root_dir}' doesn't exits") unless File.exist?(root_dir)
|
76
|
-
|
77
|
-
if path = "#{root_dir}/#{@name}.yml" and File.exist?(path)
|
78
|
-
parse_yaml(path)
|
79
|
-
end
|
80
|
-
|
81
|
-
if path = "#{root_dir}/#{@name}.yaml" and File.exist?(path)
|
82
|
-
parse_yaml(path)
|
83
|
-
end
|
84
|
-
|
85
|
-
if path = "#{root_dir}/#{@name}.csv" and File.exist?(path)
|
86
|
-
parse_csv(path)
|
87
|
-
end
|
88
|
-
|
89
|
-
return self
|
90
|
-
end
|
91
|
-
|
92
|
-
# Parse a fixture file in YAML format.
|
93
|
-
|
94
|
-
def parse_yaml(path)
|
95
|
-
require 'yaml'
|
96
|
-
|
97
|
-
str = Nitro::Template.new.render(File.read(path))
|
98
|
-
|
99
|
-
if yaml = YAML::load(str)
|
100
|
-
for name, data in yaml
|
101
|
-
self[name] = instantiate(data)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# sort the objects.
|
106
|
-
|
107
|
-
str.scan(/^(\w*?):$/).each do |key|
|
108
|
-
@objects << self[key.to_s]
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# Parse a fixture file in CSV format. Many RDBM systems and
|
113
|
-
# Spreadsheets can export to CVS, so this is a rather useful
|
114
|
-
# format.
|
115
|
-
|
116
|
-
def parse_csv(path)
|
117
|
-
require 'csv'
|
118
|
-
|
119
|
-
str = Nitro::Template.new.render(File.read(path))
|
120
|
-
|
121
|
-
reader = CSV::Reader.create(str)
|
122
|
-
header = reader.shift
|
123
|
-
|
124
|
-
reader.each_with_index do |row, i|
|
125
|
-
data = {}
|
126
|
-
row.each_with_index do |cell, j|
|
127
|
-
data[header[j].to_s.strip] = cell.to_s.strip
|
128
|
-
end
|
129
|
-
self["#{@name}_#{i+1}"] = obj = instantiate(data)
|
130
|
-
@objects << obj
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
private
|
135
|
-
|
136
|
-
# Instantiate an actual object from the Fixture data.
|
137
|
-
|
138
|
-
def instantiate(data)
|
139
|
-
obj = @klass.allocate
|
140
|
-
|
141
|
-
for key, value in data
|
142
|
-
obj.instance_variable_set("@#{key}", value)
|
143
|
-
end
|
144
|
-
|
145
|
-
return obj
|
146
|
-
end
|
147
|
-
|
148
|
-
def class_to_name(klass)
|
149
|
-
klass.to_s.demodulize.underscore
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|