baretest 0.2.4 → 0.4.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +6 -6
- data/MANIFEST.txt +40 -18
- data/README.rdoc +8 -1
- data/bin/baretest +126 -118
- data/doc/baretest.rdoc +1 -1
- data/doc/mocking_stubbing_test_doubles.rdoc +31 -3
- data/doc/news/news-0.3.0.rdoc +7 -0
- data/doc/quickref.rdoc +74 -28
- data/doc/whats_going_on.rdoc +5 -0
- data/doc/writing_tests.rdoc +25 -13
- data/examples/components/rack-test.rb +17 -0
- data/examples/{tests/irb_mode → irb_mode}/failures.rb +0 -0
- data/examples/rake/test.rake +40 -0
- data/examples/tests/01_basics_I.rb +34 -0
- data/examples/tests/02_basics_II_helpers.rb +25 -0
- data/examples/tests/03_basics_III_setup_and_teardown.rb +53 -0
- data/examples/tests/04_advanced_I_dependencies.rb +31 -0
- data/examples/tests/05_advanced_II_tags.rb +12 -0
- data/examples/tests/06_advanced_III_requires.rb +21 -0
- data/examples/tests/07_advanced_IV_components.rb +48 -0
- data/examples/tests/08_expert_I_setup_variants.rb +46 -0
- data/lib/baretest.rb +142 -21
- data/lib/baretest/assertion.rb +83 -92
- data/lib/baretest/assertion/context.rb +9 -0
- data/lib/baretest/assertion/support.rb +88 -61
- data/lib/baretest/commandline.rb +268 -0
- data/lib/baretest/formatter.rb +58 -0
- data/lib/baretest/invalidselectors.rb +24 -0
- data/lib/baretest/irb_mode.rb +100 -58
- data/lib/baretest/persistence.rb +94 -0
- data/lib/baretest/run.rb +138 -37
- data/lib/baretest/run/cli.rb +97 -43
- data/lib/baretest/run/minimal.rb +2 -1
- data/lib/baretest/run/none.rb +21 -0
- data/lib/baretest/run/xml.rb +21 -19
- data/lib/baretest/setup.rb +2 -0
- data/lib/baretest/status.rb +93 -0
- data/lib/baretest/suite.rb +185 -59
- data/lib/baretest/uid.rb +51 -0
- data/lib/baretest/use/mocha.rb +24 -0
- data/lib/baretest/use/rack_test.rb +9 -0
- data/lib/baretest/use/rr.rb +17 -0
- data/lib/baretest/version.rb +18 -4
- data/lib/command.rb +36 -0
- data/lib/command/argument.rb +11 -0
- data/lib/command/decoratinghash.rb +31 -0
- data/lib/command/definition.rb +294 -0
- data/lib/command/directorynotfounderror.rb +11 -0
- data/lib/command/env.rb +11 -0
- data/lib/command/filenotfounderror.rb +11 -0
- data/lib/command/kernel.rb +14 -0
- data/lib/command/nodirectoryerror.rb +11 -0
- data/lib/command/nofileerror.rb +11 -0
- data/lib/command/option.rb +16 -0
- data/lib/command/parser.rb +145 -0
- data/lib/command/result.rb +11 -0
- data/lib/command/types.rb +33 -0
- data/lib/command/version.rb +28 -0
- data/test/setup.rb +3 -0
- data/test/suite/lib/baretest.rb +0 -178
- data/test/suite/lib/baretest/assertion.rb +133 -112
- data/test/suite/lib/baretest/assertion/context.rb +40 -0
- data/test/suite/lib/baretest/assertion/failure.rb +19 -0
- data/test/suite/lib/baretest/assertion/skip.rb +19 -0
- data/test/suite/lib/baretest/assertion/support.rb +366 -84
- data/test/suite/lib/baretest/run.rb +114 -15
- data/test/suite/lib/baretest/suite.rb +70 -29
- metadata +46 -24
- data/examples/test.rake +0 -65
- data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
- data/examples/tests/mock_developer/test/setup.rb +0 -57
- data/examples/tests/mock_developer/test/suite/mock_demo.rb +0 -19
- data/examples/tests/overview/test.rb +0 -89
- data/examples/tests/variations/variations_01.rb +0 -14
- data/examples/tests/variations/variations_02.rb +0 -19
- data/examples/tests/variations/variations_03.rb +0 -19
- data/lib/baretest/mocha.rb +0 -18
- data/lib/baretest/rr.rb +0 -16
- data/lib/baretest/run/errors.rb +0 -49
- data/lib/baretest/skipped.rb +0 -15
- data/lib/baretest/skipped/assertion.rb +0 -20
- data/lib/baretest/skipped/suite.rb +0 -49
- data/test/external/bootstraptest.rb +0 -5
- data/test/external/bootstrapwrap.rb +0 -2
- data/test/helper/mocks.rb +0 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009-2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
|
11
|
+
# Extend Formatters that have custom options with this module to gain
|
12
|
+
# convenience methods to define the custom options.
|
13
|
+
# See Command's documentation for more information.
|
14
|
+
module Formatter
|
15
|
+
|
16
|
+
# Invoke Formatter#initialize_options
|
17
|
+
def self.extended(obj) # :nodoc:
|
18
|
+
obj.initialize_options
|
19
|
+
end
|
20
|
+
|
21
|
+
# Provides access to the command/options/arguments related information.
|
22
|
+
attr_reader :command
|
23
|
+
|
24
|
+
# Initialize some instance variables needed for the DSL.
|
25
|
+
def initialize_options # :nodoc:
|
26
|
+
@command = {
|
27
|
+
:option_defaults => {},
|
28
|
+
:elements => [],
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define default values for options.
|
33
|
+
# Example:
|
34
|
+
# option_defaults :colors => false,
|
35
|
+
# :indent => 3
|
36
|
+
def option_defaults(defaults={})
|
37
|
+
@command[:option_defaults].update(defaults)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Inject a piece of text into the helptext.
|
41
|
+
def text(*args)
|
42
|
+
@command[:elements] << [:text, args]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Use an env-variable and map it to an option.
|
46
|
+
# Example:
|
47
|
+
# env_option :indent, "INDENT"
|
48
|
+
def env_option(*args)
|
49
|
+
@command[:elements] << [:env_option, args]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Define a formatter-specific option.
|
53
|
+
# See Command::Definition#option
|
54
|
+
def option(*args)
|
55
|
+
@command[:elements] << [:option, args]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009-2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
|
11
|
+
# Raised by BareTest.process_selectors if one or more invalid selectors are
|
12
|
+
# passed in.
|
13
|
+
class InvalidSelectors < StandardError
|
14
|
+
|
15
|
+
# The selectors that are invalid
|
16
|
+
attr_reader :selectors
|
17
|
+
|
18
|
+
# Generates a standard message
|
19
|
+
def initialize(selectors) # :nodoc:
|
20
|
+
@selectors = selectors
|
21
|
+
super("Invalid selectors: #{selectors.join(', ')}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/baretest/irb_mode.rb
CHANGED
@@ -24,6 +24,17 @@ module BareTest
|
|
24
24
|
# See BareTest::IRBMode::AssertionContext for some methods IRBMode adds to Assertion for
|
25
25
|
# use within the irb session.
|
26
26
|
module IRBMode # :nodoc:
|
27
|
+
RemoveGlobals = %w[
|
28
|
+
$! $" $$ $& $' $* $+ $, $-0 $-F $-I $-K $-a $-d $-i $-l $-p $-v $-w $. $/
|
29
|
+
$0 $: $; $< $= $> $? $@ $FS $NR $OFS $ORS $PID $RS $\\ $_ $` $~
|
30
|
+
$ARGV $CHILD_STATUS $DEBUG $DEFAULT_INPUT $DEFAULT_OUTPUT $ERROR_INFO
|
31
|
+
$ERROR_POSITION $FIELD_SEPARATOR $FILENAME $IGNORECASE $INPUT_LINE_NUMBER
|
32
|
+
$INPUT_RECORD_SEPARATOR $KCODE $LAST_MATCH_INFO $LAST_PAREN_MATCH
|
33
|
+
$LAST_READ_LINE $LOADED_FEATURES $LOAD_PATH $MATCH $OUTPUT_FIELD_SEPARATOR
|
34
|
+
$OUTPUT_RECORD_SEPARATOR $POSTMATCH $PREMATCH $PROCESS_ID $PROGRAM_NAME
|
35
|
+
$SAFE $VERBOSE $stderr $stdin $stdout
|
36
|
+
]
|
37
|
+
|
27
38
|
@irb_setup = false
|
28
39
|
|
29
40
|
def self.irb_setup! # :nodoc:
|
@@ -38,35 +49,52 @@ module BareTest
|
|
38
49
|
# Adds several methods over plain Assertion.
|
39
50
|
module IRBContext
|
40
51
|
|
41
|
-
|
52
|
+
# Provides access the assertions' original status
|
53
|
+
attr_accessor :__status__
|
42
54
|
|
43
55
|
# Prints a list of available helper methods
|
44
56
|
def help
|
45
57
|
puts "Available methods:",
|
46
|
-
"s!
|
47
|
-
"
|
48
|
-
"
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"
|
56
|
-
"
|
57
|
-
"
|
58
|
+
"s! - the assertions' original status",
|
59
|
+
"sc! - the assertions' original status code",
|
60
|
+
"e! - prints the error message and full backtrace",
|
61
|
+
"em! - prints the error message",
|
62
|
+
"bt! - prints the full backtrace",
|
63
|
+
"lv! - lists all available local variables",
|
64
|
+
"iv! - lists all available instance variables",
|
65
|
+
"cv! - lists all available class variables",
|
66
|
+
"gv! - lists all available global variables, per default dropping rubys",
|
67
|
+
" standard globals (use gv!(false) to avoid that)",
|
68
|
+
"file! - the file this assertion was defined in",
|
69
|
+
"line! - the line number in the file where this assertion's definition",
|
70
|
+
" starts",
|
71
|
+
"nesting! - a >-separated list of suite descriptions this assertion is nested",
|
72
|
+
"description! - this assertion's description",
|
73
|
+
"code! - the code of this assertion",
|
58
74
|
#"restart! - Restart this irb session, resetting everything",
|
59
|
-
"irb_help
|
60
|
-
"
|
75
|
+
"irb_help - irb's original help",
|
76
|
+
"q - Quit - alias to irb's exit",
|
77
|
+
"help - this text you're reading right now"
|
61
78
|
end
|
79
|
+
alias help! help
|
62
80
|
|
63
81
|
def to_s # :nodoc:
|
64
82
|
"Context"
|
65
83
|
end
|
66
84
|
|
85
|
+
# Quit - an alias to irb's exit
|
86
|
+
def q
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
|
67
90
|
# Returns the original assertion's status
|
68
91
|
def s!
|
69
|
-
|
92
|
+
@__status__
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the original assertion's status code
|
96
|
+
def sc!
|
97
|
+
@__status__.status
|
70
98
|
end
|
71
99
|
|
72
100
|
# Prints the original assertion's error message and backtrace
|
@@ -77,20 +105,20 @@ module BareTest
|
|
77
105
|
|
78
106
|
# Prints the original assertion's error message
|
79
107
|
def em!
|
80
|
-
if @
|
81
|
-
puts @
|
82
|
-
elsif @
|
83
|
-
puts @
|
108
|
+
if @__status__.exception then
|
109
|
+
puts @__status__.exception.message
|
110
|
+
elsif @__status__.failure_reason
|
111
|
+
puts @__status__.failure_reason
|
84
112
|
else
|
85
|
-
puts "No exception
|
113
|
+
puts "No exception or failure reason available"
|
86
114
|
end
|
87
115
|
end
|
88
116
|
|
89
117
|
# Prints the original assertion's backtrace
|
90
118
|
def bt!(size=nil)
|
91
|
-
if @
|
119
|
+
if @__status__.exception then
|
92
120
|
size ||= caller.size+3
|
93
|
-
puts @
|
121
|
+
puts @__status__.exception.backtrace[0..-size]
|
94
122
|
else
|
95
123
|
puts "No exception occurred, therefore no backtrace is available"
|
96
124
|
end
|
@@ -107,31 +135,47 @@ module BareTest
|
|
107
135
|
end
|
108
136
|
|
109
137
|
# Returns an array of all global variable names
|
110
|
-
def gv!
|
111
|
-
puts *global_variables.sort
|
138
|
+
def gv!(remove_standard=true)
|
139
|
+
puts *(global_variables-(remove_standard ? IRBMode::RemoveGlobals : [])).sort
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the original assertion's file
|
143
|
+
def file!
|
144
|
+
puts @__assertion__.file
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the original assertion's line
|
148
|
+
def line!
|
149
|
+
puts @__assertion__.line
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns the original assertion's line
|
153
|
+
def open!
|
154
|
+
`bbedit '#{@__assertion__.file}:#{@__assertion__.line}'`
|
112
155
|
end
|
113
156
|
|
114
157
|
# Prints a string of the original assertion's nesting within suites
|
115
|
-
def description
|
116
|
-
puts @
|
158
|
+
def description!
|
159
|
+
puts @__assertion__.description
|
117
160
|
end
|
118
161
|
|
119
162
|
# Prints a string of the original assertion's nesting within suites
|
120
|
-
def nesting
|
121
|
-
puts @
|
163
|
+
def nesting!
|
164
|
+
puts @__assertion__.suite.ancestors[0..-2].reverse.map { |s| s.description }.join(' > ')
|
122
165
|
end
|
123
166
|
|
124
167
|
# Prints the code of the assertion
|
125
168
|
# Be aware that this relies on your code being properly indented.
|
126
169
|
def code!
|
127
|
-
if code = @
|
128
|
-
puts(insert_line_numbers(code, @
|
170
|
+
if code = @__assertion__.code then
|
171
|
+
puts(insert_line_numbers(code, @__assertion__.line-1))
|
129
172
|
else
|
130
173
|
puts "Code could not be extracted"
|
131
174
|
end
|
132
175
|
end
|
133
176
|
|
134
|
-
|
177
|
+
# Prepend the line number in front of ever line
|
178
|
+
def insert_line_numbers(code, start_line=1) # :nodoc:
|
135
179
|
digits = Math.log10(start_line+code.count("\n")).floor+1
|
136
180
|
current_line = start_line-1
|
137
181
|
code.gsub(/^/) { sprintf ' %0*d ', digits, current_line+=1 }
|
@@ -152,48 +196,50 @@ module BareTest
|
|
152
196
|
# Formatter callback.
|
153
197
|
# Invoked once for every assertion.
|
154
198
|
# Gets the assertion to run as single argument.
|
155
|
-
def run_test(assertion,
|
199
|
+
def run_test(assertion, with_setup)
|
156
200
|
rv = super
|
157
201
|
# drop into irb if assertion failed
|
158
202
|
case rv.status
|
159
203
|
when :failure
|
160
|
-
start_irb_failure_mode(assertion)
|
161
|
-
irb_mode_for_assertion(assertion)
|
162
|
-
stop_irb_mode
|
204
|
+
start_irb_failure_mode(assertion, rv)
|
205
|
+
irb_mode_for_assertion(assertion, rv, with_setup)
|
206
|
+
stop_irb_mode
|
163
207
|
when :error
|
164
|
-
start_irb_error_mode(assertion)
|
165
|
-
irb_mode_for_assertion(assertion)
|
166
|
-
stop_irb_mode
|
208
|
+
start_irb_error_mode(assertion, rv)
|
209
|
+
irb_mode_for_assertion(assertion, rv, with_setup)
|
210
|
+
stop_irb_mode
|
211
|
+
# with other states, irb-mode is not started
|
167
212
|
end
|
168
213
|
|
169
214
|
rv
|
170
215
|
end
|
171
216
|
|
172
217
|
# Invoked when we have to drop into irb mode due to a failure
|
173
|
-
def start_irb_failure_mode(assertion) # :nodoc:
|
218
|
+
def start_irb_failure_mode(assertion, status) # :nodoc:
|
174
219
|
ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }
|
175
220
|
|
176
221
|
puts
|
177
|
-
puts "#{
|
222
|
+
puts "#{status.status.to_s.capitalize} in: #{ancestry[1..-1].join(' > ')}"
|
178
223
|
puts "Description: #{assertion.description}"
|
179
224
|
if file = assertion.file then
|
180
|
-
code = irb_code_reindented(file, assertion.line-1,
|
225
|
+
code = irb_code_reindented(file, assertion.line-1,25)
|
181
226
|
match = code.match(/\n^ [^ ]/)
|
182
|
-
code[-(match.post_match.size-3)..-1] = ""
|
227
|
+
code[-(match.post_match.size-3)..-1] = "" if match
|
228
|
+
code << "\n... (only showing first 25 lines)" unless match
|
183
229
|
assertion.code = code
|
184
230
|
puts "Code (#{file}):", insert_line_numbers(code, assertion.line-1)
|
185
231
|
end
|
186
232
|
end
|
187
233
|
|
188
234
|
# Invoked when we have to drop into irb mode due to an error
|
189
|
-
def start_irb_error_mode(assertion) # :nodoc:
|
235
|
+
def start_irb_error_mode(assertion, status) # :nodoc:
|
190
236
|
ancestry = assertion.suite.ancestors.reverse.map { |suite| suite.description }
|
191
237
|
|
192
238
|
puts
|
193
|
-
puts "#{
|
239
|
+
puts "#{status.status.to_s.capitalize} in: #{ancestry[1..-1].join(' > ')}"
|
194
240
|
puts "Description: #{assertion.description}"
|
195
|
-
puts "Exception: #{
|
196
|
-
if assertion.file && match =
|
241
|
+
puts "Exception: #{status.exception} in file #{status.exception.backtrace.first}"
|
242
|
+
if assertion.file && match = status.exception.backtrace.first.match(/^([^:]+):(\d+)(?:$|:in .*)/) then
|
197
243
|
file, line = match.captures
|
198
244
|
file = File.expand_path(file)
|
199
245
|
if assertion.file == file then
|
@@ -225,13 +271,11 @@ module BareTest
|
|
225
271
|
# Drop into an irb shell in the context of the assertion passed as an argument.
|
226
272
|
# Uses Assertion#clean_copy(AssertionContext) to create the context.
|
227
273
|
# Adds the code into irb's history.
|
228
|
-
def irb_mode_for_assertion(
|
229
|
-
|
230
|
-
assertion.reset
|
231
|
-
irb_context = assertion.context
|
274
|
+
def irb_mode_for_assertion(assertion, status, with_setup) # :nodoc:
|
275
|
+
irb_context = ::BareTest::Assertion::Context.new(assertion)
|
232
276
|
irb_context.extend IRBContext
|
233
|
-
irb_context.
|
234
|
-
assertion.setup
|
277
|
+
irb_context.__status__ = status
|
278
|
+
assertion.execute_phase(:setup, irb_context, with_setup.map { |s| s.block })
|
235
279
|
|
236
280
|
$stdout = StringIO.new # HAX - silencing 'irb: warn: can't alias help from irb_help.' - find a better way
|
237
281
|
irb = IRB::Irb.new(IRB::WorkSpace.new(irb_context))
|
@@ -243,21 +287,19 @@ module BareTest
|
|
243
287
|
|
244
288
|
trap("SIGINT") do irb.signal_handle end
|
245
289
|
|
246
|
-
if code =
|
290
|
+
if code = assertion.code then
|
247
291
|
#irb_context.code = code
|
248
292
|
Readline::HISTORY.push(*code.split("\n")[1..-2])
|
249
293
|
end
|
250
294
|
|
251
295
|
catch(:IRB_EXIT) do irb.eval_input end
|
252
296
|
|
253
|
-
assertion.teardown
|
297
|
+
assertion.execute_phase(:teardown, irb_context, assertion.suite.ancestry_teardown)
|
254
298
|
end
|
255
299
|
|
256
300
|
# Invoked when we leave the irb session
|
257
|
-
def stop_irb_mode
|
301
|
+
def stop_irb_mode # :nodoc:
|
258
302
|
puts
|
259
|
-
super
|
260
|
-
rescue NoMethodError # HAX, not happy about that. necessary due to order of extend
|
261
303
|
end
|
262
304
|
end
|
263
305
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009-2010 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'baretest/uid'
|
10
|
+
require 'yaml'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
module BareTest
|
16
|
+
|
17
|
+
class Persistence
|
18
|
+
|
19
|
+
# The default storage path base (~/.baretest)
|
20
|
+
def self.storage_path
|
21
|
+
File.expand_path('~/.baretest')
|
22
|
+
end
|
23
|
+
|
24
|
+
# BareTest uses a file of the form '.baretest_id_*' (where * is a 32 digits
|
25
|
+
# long hex) to uniquely identify a project. This ID is then used to
|
26
|
+
# associate stored data with the project.
|
27
|
+
def self.determine_project_id(project_dir)
|
28
|
+
found = Dir.glob("#{project_dir}/.baretest_id_*") { |path|
|
29
|
+
break $1 if File.file?(path) && path =~ /id_([A-Fa-f0-9]{32})$/
|
30
|
+
}
|
31
|
+
unless found then
|
32
|
+
found = UID.hex_uid
|
33
|
+
File.open(".baretest_id_#{found}", "w") {} # no File::touch, evil
|
34
|
+
end
|
35
|
+
|
36
|
+
found
|
37
|
+
end
|
38
|
+
|
39
|
+
# The directory this Persistence instance stores its data
|
40
|
+
attr_reader :storage_dir
|
41
|
+
|
42
|
+
# The directory of the project this Persistence instance is attached to
|
43
|
+
attr_reader :project_dir
|
44
|
+
|
45
|
+
# The id of the project this Persistence instance is attached to
|
46
|
+
attr_reader :project_id
|
47
|
+
|
48
|
+
# Arguments:
|
49
|
+
# project_dir:: The directory of the project
|
50
|
+
# storage_dir:: The directory where this Persistence instance should store
|
51
|
+
# its data
|
52
|
+
def initialize(project_dir=nil, storage_dir=nil)
|
53
|
+
@storage_dir = File.expand_path(storage_dir || self.class.storage_path)
|
54
|
+
@project_dir = File.expand_path(project_dir || ".")
|
55
|
+
@project_id = self.class.determine_project_id(@project_dir)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Stores data to a file.
|
59
|
+
#
|
60
|
+
# === Arguments
|
61
|
+
# filename:: A relative path. Directories are created on the fly if
|
62
|
+
# necessary. Must not be an absolute path. The path is relative
|
63
|
+
# to Persistence#storage_dir
|
64
|
+
# data:: The data to store. Anything that can be serialized by YAML.
|
65
|
+
# This excludes IOs and Procs.
|
66
|
+
def store(filename, data)
|
67
|
+
raise "Invalid filename: #{filename}" unless filename =~ %r{\A[A-Za-z0-9_-][A-Za-z0-9_-]*\z}
|
68
|
+
dir = "#{@storage_dir}/#{@project_id}"
|
69
|
+
FileUtils.mkdir_p(dir)
|
70
|
+
File.open("#{dir}/#{filename}.yaml", "w") do |fh|
|
71
|
+
fh.write(data.to_yaml)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Reads and deserializes the data in a given filename.
|
76
|
+
# filename:: A relative path. Directories are created on the fly if
|
77
|
+
# necessary. Must not be an absolute path. The path is relative
|
78
|
+
# to Persistence#storage_dir
|
79
|
+
# default:: The value to return in case the file does not exist.
|
80
|
+
# Alternatively you can pass a block that calculates the default.
|
81
|
+
def read(filename, default=nil)
|
82
|
+
raise "Invalid filename: #{filename}" if filename =~ %r{\A\.\./|/\.\./\z}
|
83
|
+
path = "#{@storage_dir}/#{@project_id}/#{filename}.yaml"
|
84
|
+
|
85
|
+
if File.exist?(path)
|
86
|
+
YAML.load_file(path)
|
87
|
+
elsif block_given?
|
88
|
+
yield
|
89
|
+
else
|
90
|
+
default
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|