xing-backend 0.0.19 → 0.0.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/role.rb +24 -0
- data/config/locales/json.yml +29 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20140828011806_initial.rb +45 -0
- data/db/migrate/20140914030703_devise_token_auth_add_token_info_to_users.rb +20 -0
- data/db/migrate/20140929192921_remove_login_from_users.rb +5 -0
- data/lib/xing-backend.rb +1 -0
- data/lib/xing/engine.rb +4 -0
- data/lib/xing/nominal/database_config_validator.rb +31 -0
- data/lib/xing/nominal/dependency_utils.rb +26 -0
- data/lib/xing/nominal/secrets_validator.rb +50 -0
- data/lib/xing/nominal/yaml_config_validator.rb +44 -0
- data/lib/xing/services.rb +0 -2
- data/lib/xing/services/class_registry.rb +31 -0
- data/lib/xing/services/{page_wrapper.rb → paged_wrapper.rb} +2 -2
- data/lib/xing/snapshot.rb +4 -0
- data/lib/xing/snapshot/domain_helpers.rb +24 -0
- data/lib/xing/snapshot/fetcher.rb +35 -0
- data/lib/xing/snapshot/local_site_snapshot.rb +37 -0
- data/lib/xing/snapshot/remote_site_snapshot.rb +16 -0
- data/lib/xing/snapshot/site_page_set.rb +29 -0
- data/lib/xing/snapshot/site_snapshot.rb +41 -0
- data/lib/xing/snapshot/sitemap.rb +68 -0
- data/lib/xing/snapshot/writer.rb +15 -0
- data/lib/xing/spec_helpers.rb +7 -0
- data/lib/xing/spec_helpers/api_response_matchers.rb +26 -0
- data/lib/xing/spec_helpers/ci_support.rb +6 -0
- data/lib/xing/spec_helpers/dom_equiv.rb +26 -0
- data/lib/xing/spec_helpers/json_requests.rb +58 -0
- data/lib/xing/spec_helpers/routing_spec_patch.rb +28 -0
- data/lib/xing/spec_helpers/split_servers.rb +15 -0
- data/lib/xing/spec_helpers/test_url_helpers.rb +5 -0
- data/lib/xing/static.rb +1 -0
- data/lib/xing/static/backend_url_cookie.rb +16 -0
- data/lib/xing/static/goto_param.rb +30 -0
- data/lib/xing/static/logger.rb +11 -0
- data/lib/xing/static/rack_app.rb +40 -0
- data/lib/xing/tasks/all.rake +4 -0
- data/lib/xing/tasks/db_recycle.rake +4 -0
- data/lib/xing/tasks/dependencies_common.rake +49 -0
- data/lib/xing/tasks/sample_data.rake +49 -0
- data/lib/xing/tasks/take_snapshot.rake +4 -0
- data/spec/xing/builders/list_builder_spec.rb +0 -2
- data/spec/xing/builders/ordered_list_builder_spec.rb +0 -2
- data/spec/xing/nominal/database_config_validator_spec.rb +98 -0
- data/spec/xing/nominal/secrets_validator_spec.rb +78 -0
- data/spec/xing/serializers/list_spec.rb +116 -0
- data/spec/xing/serializers/paged_index_spec.rb +2 -2
- data/spec/xing/serializers/paged_list_spec.rb +1 -1
- data/spec/xing/services/error_converter_spec.rb +1 -3
- data/spec/xing/services/paged_wrapper_spec.rb +30 -0
- data/spec/xing/snapshot/remote_snapshot_fetcher_spec.rb +81 -0
- data/spec/xing/{services → snapshot}/snapshot_fetcher_spec.rb +6 -4
- data/spec_help/dummy/db/test.sqlite3 +0 -0
- data/spec_help/dummy/log/test.log +143 -0
- data/spec_help/file-sandbox.rb +164 -0
- data/spec_help/spec_helper.rb +0 -2
- metadata +152 -12
- data/lib/xing/services/snapshot_fetcher.rb +0 -33
- data/lib/xing/services/snapshot_writer.rb +0 -19
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'xing/serializers/paged_index'
|
2
|
-
require 'xing/services/
|
2
|
+
require 'xing/services/paged_wrapper'
|
3
3
|
|
4
4
|
describe Xing::Serializers::PagedIndex do
|
5
5
|
class PageIndexSerializer < Xing::Serializers::PagedIndex
|
@@ -39,7 +39,7 @@ describe Xing::Serializers::PagedIndex do
|
|
39
39
|
|
40
40
|
describe 'as_json' do
|
41
41
|
let :serializer do
|
42
|
-
PageIndexSerializer.new(Xing::Services::
|
42
|
+
PageIndexSerializer.new(Xing::Services::PagedWrapper.new(list, page_num, total_items, per_page))
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should generate a JSON with the proper links and self" do
|
@@ -42,7 +42,7 @@ describe Xing::Serializers::PagedList do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
let :serializer do
|
45
|
-
PageSerializer.new(Xing::Services::
|
45
|
+
PageSerializer.new(Xing::Services::PagedWrapper.new(list, page_num, total_items, per_page))
|
46
46
|
end
|
47
47
|
|
48
48
|
let :json do
|
@@ -10,9 +10,7 @@ describe Xing::Services::ErrorConverter do
|
|
10
10
|
before do
|
11
11
|
# ensure that I18n can find the translation file needed for error
|
12
12
|
# conversions
|
13
|
-
I18n.load_path += Dir[File.join(File.dirname(__FILE__),'../../..', 'config', 'locales', '*.{rb,yml}')
|
14
|
-
puts dirn
|
15
|
-
end]
|
13
|
+
I18n.load_path += Dir[File.join(File.dirname(__FILE__),'../../..', 'config', 'locales', '*.{rb,yml}')]
|
16
14
|
end
|
17
15
|
|
18
16
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'xing/services/paged_wrapper'
|
2
|
+
|
3
|
+
describe Xing::Services::PagedWrapper do
|
4
|
+
let :list do
|
5
|
+
[ :a, :b, :c ]
|
6
|
+
end
|
7
|
+
|
8
|
+
let :per_page do
|
9
|
+
3
|
10
|
+
end
|
11
|
+
|
12
|
+
let :total_items do
|
13
|
+
14
|
14
|
+
end
|
15
|
+
|
16
|
+
let :page_num do
|
17
|
+
2
|
18
|
+
end
|
19
|
+
|
20
|
+
subject :wrapper do
|
21
|
+
Xing::Services::PagedWrapper.new(list, page_num, total_items, per_page)
|
22
|
+
end
|
23
|
+
|
24
|
+
it{ expect(subject.current_page).to eq(page_num) }
|
25
|
+
it{ expect(subject.total_count).to eq(total_items) }
|
26
|
+
it{ expect(subject.limit_value).to eq(per_page) }
|
27
|
+
|
28
|
+
it{ expect(subject.total_pages).to eq(5) }
|
29
|
+
it{ expect(subject.map(&:to_s)).to eq(%w[a b c])}
|
30
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'xing/snapshot/fetcher'
|
2
|
+
require 'file-sandbox'
|
3
|
+
|
4
|
+
describe Xing::Snapshot::Fetcher do
|
5
|
+
include FileSandbox
|
6
|
+
|
7
|
+
let :server_secrets do
|
8
|
+
{ 'url' => 'http://snapshot-server.com',
|
9
|
+
'user' => 'foobar',
|
10
|
+
'password' => 'my_password'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
allow(Rails).to receive_message_chain(:application, :secrets, :snapshot_server).and_return(server_secrets)
|
16
|
+
allow(Rails).to receive(:root).and_return(@sandbox.root)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "if remote succeeds" do
|
20
|
+
before do
|
21
|
+
begin
|
22
|
+
#FileUtils.mkdir_p("#{ Rails.root }/spec/fixtures/sitemap_scratch")
|
23
|
+
#File.delete("#{ Rails.root }/spec/fixtures/sitemap_scratch/test.html")
|
24
|
+
rescue
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# This feels like way too much mocking, but dont know how to test without
|
29
|
+
# completely
|
30
|
+
# turning off selenium
|
31
|
+
before do
|
32
|
+
response = Typhoeus::Response.new(code: 200, body: "some html content")
|
33
|
+
Typhoeus.stub(server_secrets['url']).and_return(response)
|
34
|
+
expect(Typhoeus::Request).to receive(:new).with(
|
35
|
+
server_secrets['url'],
|
36
|
+
:userpwd => "#{server_secrets['user']}:#{server_secrets['password']}",
|
37
|
+
:params => { :url => "http://www.awesome.com/test" }
|
38
|
+
).and_call_original
|
39
|
+
end
|
40
|
+
|
41
|
+
subject :remote_snapshot_fetcher do
|
42
|
+
Xing::Snapshot::Fetcher.new
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should read html contents from remote server and output to the file" do
|
46
|
+
remote_snapshot_fetcher.perform("http://www.awesome.com", "test")
|
47
|
+
content = File.read("public/frontend_snapshots/test.html")
|
48
|
+
expect(content).to eq("some html content")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "if remote fails" do
|
53
|
+
before do
|
54
|
+
response = Typhoeus::Response.new(code: 500, status_message: "failed", body: "a backtrace")
|
55
|
+
Typhoeus.stub(server_secrets['url']).and_return(response)
|
56
|
+
expect(Typhoeus::Request).to receive(:new).with(
|
57
|
+
server_secrets['url'],
|
58
|
+
:userpwd => "#{server_secrets['user']}:#{server_secrets['password']}",
|
59
|
+
:params => { :url => "http://www.awesome.com/test" }
|
60
|
+
).and_call_original
|
61
|
+
end
|
62
|
+
|
63
|
+
let :logger do
|
64
|
+
double("Logger")
|
65
|
+
end
|
66
|
+
|
67
|
+
subject :remote_snapshot_fetcher do
|
68
|
+
Xing::Snapshot::Fetcher.new.tap do |fetcher|
|
69
|
+
allow(fetcher).to receive(:logger).and_return(logger)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should read html contents from remote server and output to the file" do
|
74
|
+
expect(logger).to receive(:warn).with(/failed/)
|
75
|
+
expect(logger).to receive(:warn).with(/a backtrace/)
|
76
|
+
expect do
|
77
|
+
remote_snapshot_fetcher.perform("http://www.awesome.com", "test")
|
78
|
+
end.to raise_error(/Query.*failed/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
require 'xing/
|
2
|
-
require '
|
1
|
+
require 'xing/snapshot/fetcher'
|
2
|
+
require 'file-sandbox'
|
3
3
|
|
4
4
|
|
5
|
-
describe Xing::
|
5
|
+
describe Xing::Snapshot::Fetcher do
|
6
|
+
include FileSandbox
|
7
|
+
|
6
8
|
let :server_secrets do
|
7
9
|
{ 'url' => 'http://snapshot-server.com',
|
8
10
|
'user' => 'foobar',
|
@@ -13,7 +15,7 @@ describe Xing::Services::SnapshotFetcher do
|
|
13
15
|
let :mock_request do double('request') end
|
14
16
|
let :mock_response do double('a response') end
|
15
17
|
let :fetcher do
|
16
|
-
Xing::
|
18
|
+
Xing::Snapshot::Fetcher.new
|
17
19
|
end
|
18
20
|
|
19
21
|
before do
|
File without changes
|
@@ -0,0 +1,143 @@
|
|
1
|
+
ETHON: Libcurl initialized
|
2
|
+
ETHON: started MULTI
|
3
|
+
ETHON: performed MULTI
|
4
|
+
ETHON: Libcurl initialized
|
5
|
+
ETHON: started MULTI
|
6
|
+
ETHON: performed MULTI
|
7
|
+
ETHON: started MULTI
|
8
|
+
ETHON: performed MULTI
|
9
|
+
ETHON: Libcurl initialized
|
10
|
+
ETHON: started MULTI
|
11
|
+
ETHON: performed MULTI
|
12
|
+
ETHON: started MULTI
|
13
|
+
ETHON: performed MULTI
|
14
|
+
ETHON: Libcurl initialized
|
15
|
+
ETHON: started MULTI
|
16
|
+
ETHON: performed MULTI
|
17
|
+
ETHON: started MULTI
|
18
|
+
ETHON: performed MULTI
|
19
|
+
ETHON: Libcurl initialized
|
20
|
+
ETHON: started MULTI
|
21
|
+
ETHON: performed MULTI
|
22
|
+
ETHON: started MULTI
|
23
|
+
ETHON: performed MULTI
|
24
|
+
ETHON: Libcurl initialized
|
25
|
+
ETHON: started MULTI
|
26
|
+
ETHON: performed MULTI
|
27
|
+
ETHON: started MULTI
|
28
|
+
ETHON: performed MULTI
|
29
|
+
ETHON: Libcurl initialized
|
30
|
+
ETHON: started MULTI
|
31
|
+
ETHON: performed MULTI
|
32
|
+
ETHON: started MULTI
|
33
|
+
ETHON: performed MULTI
|
34
|
+
ETHON: Libcurl initialized
|
35
|
+
ETHON: started MULTI
|
36
|
+
ETHON: performed MULTI
|
37
|
+
ETHON: started MULTI
|
38
|
+
ETHON: performed MULTI
|
39
|
+
ETHON: Libcurl initialized
|
40
|
+
ETHON: started MULTI
|
41
|
+
ETHON: performed MULTI
|
42
|
+
ETHON: started MULTI
|
43
|
+
ETHON: performed MULTI
|
44
|
+
ETHON: Libcurl initialized
|
45
|
+
ETHON: started MULTI
|
46
|
+
ETHON: performed MULTI
|
47
|
+
ETHON: started MULTI
|
48
|
+
ETHON: performed MULTI
|
49
|
+
ETHON: Libcurl initialized
|
50
|
+
ETHON: started MULTI
|
51
|
+
ETHON: performed MULTI
|
52
|
+
ETHON: started MULTI
|
53
|
+
ETHON: performed MULTI
|
54
|
+
ETHON: Libcurl initialized
|
55
|
+
ETHON: started MULTI
|
56
|
+
ETHON: performed MULTI
|
57
|
+
ETHON: started MULTI
|
58
|
+
ETHON: performed MULTI
|
59
|
+
ETHON: Libcurl initialized
|
60
|
+
ETHON: started MULTI
|
61
|
+
ETHON: performed MULTI
|
62
|
+
ETHON: started MULTI
|
63
|
+
ETHON: performed MULTI
|
64
|
+
ETHON: Libcurl initialized
|
65
|
+
ETHON: started MULTI
|
66
|
+
ETHON: performed MULTI
|
67
|
+
ETHON: started MULTI
|
68
|
+
ETHON: performed MULTI
|
69
|
+
ETHON: Libcurl initialized
|
70
|
+
ETHON: started MULTI
|
71
|
+
ETHON: performed MULTI
|
72
|
+
ETHON: started MULTI
|
73
|
+
ETHON: performed MULTI
|
74
|
+
ETHON: Libcurl initialized
|
75
|
+
ETHON: started MULTI
|
76
|
+
ETHON: performed MULTI
|
77
|
+
ETHON: started MULTI
|
78
|
+
ETHON: performed MULTI
|
79
|
+
ETHON: Libcurl initialized
|
80
|
+
ETHON: started MULTI
|
81
|
+
ETHON: performed MULTI
|
82
|
+
ETHON: started MULTI
|
83
|
+
ETHON: performed MULTI
|
84
|
+
ETHON: Libcurl initialized
|
85
|
+
ETHON: started MULTI
|
86
|
+
ETHON: performed MULTI
|
87
|
+
ETHON: started MULTI
|
88
|
+
ETHON: performed MULTI
|
89
|
+
ETHON: Libcurl initialized
|
90
|
+
ETHON: started MULTI
|
91
|
+
ETHON: performed MULTI
|
92
|
+
ETHON: started MULTI
|
93
|
+
ETHON: performed MULTI
|
94
|
+
ETHON: Libcurl initialized
|
95
|
+
ETHON: started MULTI
|
96
|
+
ETHON: performed MULTI
|
97
|
+
ETHON: started MULTI
|
98
|
+
ETHON: performed MULTI
|
99
|
+
ETHON: Libcurl initialized
|
100
|
+
ETHON: started MULTI
|
101
|
+
ETHON: performed MULTI
|
102
|
+
ETHON: started MULTI
|
103
|
+
ETHON: performed MULTI
|
104
|
+
ETHON: Libcurl initialized
|
105
|
+
ETHON: started MULTI
|
106
|
+
ETHON: performed MULTI
|
107
|
+
ETHON: started MULTI
|
108
|
+
ETHON: performed MULTI
|
109
|
+
ETHON: Libcurl initialized
|
110
|
+
ETHON: started MULTI
|
111
|
+
ETHON: performed MULTI
|
112
|
+
ETHON: started MULTI
|
113
|
+
ETHON: performed MULTI
|
114
|
+
ETHON: Libcurl initialized
|
115
|
+
ETHON: started MULTI
|
116
|
+
ETHON: performed MULTI
|
117
|
+
ETHON: started MULTI
|
118
|
+
ETHON: performed MULTI
|
119
|
+
ETHON: Libcurl initialized
|
120
|
+
ETHON: started MULTI
|
121
|
+
ETHON: performed MULTI
|
122
|
+
ETHON: started MULTI
|
123
|
+
ETHON: performed MULTI
|
124
|
+
ETHON: Libcurl initialized
|
125
|
+
ETHON: started MULTI
|
126
|
+
ETHON: performed MULTI
|
127
|
+
ETHON: started MULTI
|
128
|
+
ETHON: performed MULTI
|
129
|
+
ETHON: Libcurl initialized
|
130
|
+
ETHON: started MULTI
|
131
|
+
ETHON: performed MULTI
|
132
|
+
ETHON: started MULTI
|
133
|
+
ETHON: performed MULTI
|
134
|
+
ETHON: Libcurl initialized
|
135
|
+
ETHON: started MULTI
|
136
|
+
ETHON: performed MULTI
|
137
|
+
ETHON: started MULTI
|
138
|
+
ETHON: performed MULTI
|
139
|
+
ETHON: Libcurl initialized
|
140
|
+
ETHON: started MULTI
|
141
|
+
ETHON: performed MULTI
|
142
|
+
ETHON: started MULTI
|
143
|
+
ETHON: performed MULTI
|
@@ -0,0 +1,164 @@
|
|
1
|
+
#require 'ftools'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module FileSandbox
|
5
|
+
def self.included(spec)
|
6
|
+
return unless spec.respond_to? :before
|
7
|
+
|
8
|
+
spec.before do
|
9
|
+
setup_sandbox
|
10
|
+
end
|
11
|
+
|
12
|
+
spec.after do
|
13
|
+
teardown_sandbox
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class HaveContents
|
18
|
+
def initialize(contents)
|
19
|
+
@contents = contents
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(target)
|
23
|
+
case @contents
|
24
|
+
when Regexp
|
25
|
+
@contents =~ target.contents
|
26
|
+
when String
|
27
|
+
@contents == target.contents
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def have_contents(expected)
|
33
|
+
HaveContents.new(expected)
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :sandbox
|
37
|
+
|
38
|
+
def in_sandbox(&block)
|
39
|
+
raise "I expected to create a sandbox as you passed in a block to me" if !block_given?
|
40
|
+
|
41
|
+
setup_sandbox
|
42
|
+
original_error = nil
|
43
|
+
|
44
|
+
begin
|
45
|
+
yield @sandbox
|
46
|
+
rescue => e
|
47
|
+
original_error = e
|
48
|
+
raise
|
49
|
+
ensure
|
50
|
+
begin
|
51
|
+
teardown_sandbox
|
52
|
+
rescue
|
53
|
+
if original_error
|
54
|
+
STDERR.puts "ALERT: a test raised an error and failed to release some lock(s) in the sandbox directory"
|
55
|
+
raise(original_error)
|
56
|
+
else
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def setup_sandbox(path = '__sandbox')
|
64
|
+
unless @sandbox
|
65
|
+
@sandbox = Sandbox.new(path)
|
66
|
+
@__old_path_for_sandbox = Dir.pwd
|
67
|
+
Dir.chdir(@sandbox.root)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def teardown_sandbox
|
72
|
+
if @sandbox
|
73
|
+
Dir.chdir(@__old_path_for_sandbox)
|
74
|
+
@sandbox.clean_up
|
75
|
+
@sandbox = nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Sandbox
|
80
|
+
attr_reader :root
|
81
|
+
|
82
|
+
def initialize(path = '__sandbox')
|
83
|
+
@root = File.expand_path(path)
|
84
|
+
clean_up
|
85
|
+
FileUtils.mkdir_p @root
|
86
|
+
end
|
87
|
+
|
88
|
+
def [](name)
|
89
|
+
SandboxFile.new(File.join(@root, name), name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# usage new :file=>'my file.rb', :with_contents=>'some stuff'
|
93
|
+
def new(options)
|
94
|
+
if options.has_key? :directory
|
95
|
+
dir = self[options.delete(:directory)]
|
96
|
+
FileUtils.mkdir_p dir.path
|
97
|
+
else
|
98
|
+
file = self[options.delete(:file)]
|
99
|
+
if (binary_content = options.delete(:with_binary_content) || options.delete(:with_binary_contents))
|
100
|
+
file.binary_content = binary_content
|
101
|
+
else
|
102
|
+
file.content = (options.delete(:with_content) || options.delete(:with_contents) || '')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
raise "unexpected keys '#{options.keys.join(', ')}'" unless options.empty?
|
107
|
+
|
108
|
+
dir || file
|
109
|
+
end
|
110
|
+
|
111
|
+
def remove(options)
|
112
|
+
name = File.join(@root, options[:file])
|
113
|
+
FileUtils.remove_file name
|
114
|
+
end
|
115
|
+
|
116
|
+
def clean_up
|
117
|
+
FileUtils.rm_rf @root
|
118
|
+
if File.exists? @root
|
119
|
+
raise "Could not remove directory #{@root.inspect}, something is probably still holding a lock on it"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
class SandboxFile
|
126
|
+
attr_reader :path
|
127
|
+
|
128
|
+
def initialize(path, sandbox_path)
|
129
|
+
@path = path
|
130
|
+
@sandbox_path = sandbox_path
|
131
|
+
end
|
132
|
+
|
133
|
+
def inspect
|
134
|
+
"SandboxFile: #@sandbox_path"
|
135
|
+
end
|
136
|
+
|
137
|
+
def exist?
|
138
|
+
File.exist? path
|
139
|
+
end
|
140
|
+
|
141
|
+
def content
|
142
|
+
File.read path
|
143
|
+
end
|
144
|
+
|
145
|
+
def content=(content)
|
146
|
+
FileUtils.mkdir_p File.dirname(@path)
|
147
|
+
File.open(@path, "w") {|f| f << content}
|
148
|
+
end
|
149
|
+
|
150
|
+
def binary_content=(content)
|
151
|
+
FileUtils.mkdir_p File.dirname(@path)
|
152
|
+
File.open(@path, "wb") {|f| f << content}
|
153
|
+
end
|
154
|
+
|
155
|
+
def create
|
156
|
+
self.content = ''
|
157
|
+
end
|
158
|
+
|
159
|
+
alias exists? exist?
|
160
|
+
alias contents content
|
161
|
+
alias contents= content=
|
162
|
+
alias binary_contents= binary_content=
|
163
|
+
end
|
164
|
+
end
|