baretest 0.2.4 → 0.4.0.pre1
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/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
|