smalruby-editor 0.0.8-x86-mingw32
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.
Potentially problematic release.
This version of smalruby-editor might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/.rspec +4 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/.simplecov +7 -0
- data/.travis.yml +23 -0
- data/LEGAL +13 -0
- data/LICENSE +22 -0
- data/Procfile +1 -0
- data/README.rdoc +46 -0
- data/Rakefile +9 -0
- data/app/assets/images/.keep +0 -0
- data/app/assets/images/favicon.ico +0 -0
- data/app/assets/javascripts/application.js +21 -0
- data/app/assets/javascripts/editor.js.coffee.erb +139 -0
- data/app/assets/stylesheets/application.css +19 -0
- data/app/assets/stylesheets/editor.css.scss +19 -0
- data/app/assets/stylesheets/flatstrap-custom.css.scss +2 -0
- data/app/controllers/application_controller.rb +5 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/editor_controller.rb +5 -0
- data/app/controllers/source_codes_controller.rb +106 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/editor_helper.rb +2 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/source_code.rb +49 -0
- data/app/views/editor/index.html.erb +23 -0
- data/app/views/layouts/application.html.erb +15 -0
- data/bin/bundle +3 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/bin/smalruby-editor +80 -0
- data/config/application.rb +16 -0
- data/config/boot.rb +17 -0
- data/config/database.yml.mysql2 +48 -0
- data/config/database.yml.sqlite3 +31 -0
- data/config/database.yml.travis +5 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +30 -0
- data/config/environments/production.rb +86 -0
- data/config/environments/standalone.rb +16 -0
- data/config/environments/test.rb +46 -0
- data/config/initializers/backtrace_silencers.rb +9 -0
- data/config/initializers/filter_parameter_logging.rb +4 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/secret_token.rb +17 -0
- data/config/initializers/session_store.rb +4 -0
- data/config/initializers/wrap_parameters.rb +15 -0
- data/config/locales/en.yml +23 -0
- data/config/routes.rb +68 -0
- data/config/unicorn.rb +23 -0
- data/config.ru +4 -0
- data/db/migrate/20131216121603_create_source_codes.rb +9 -0
- data/db/migrate/20131219045113_add_filename_to_source_code.rb +5 -0
- data/db/schema.rb +23 -0
- data/db/seeds.rb +7 -0
- data/lib/assets/.keep +0 -0
- data/lib/smalruby_editor/version.rb +3 -0
- data/lib/smalruby_editor.rb +46 -0
- data/lib/tasks/.keep +0 -0
- data/lib/tasks/gem.rake +10 -0
- data/lib/tasks/rspec.rake +16 -0
- data/lib/tasks/rubocop.rake +3 -0
- data/log/.keep +0 -0
- data/public/404.html +58 -0
- data/public/422.html +58 -0
- data/public/500.html +57 -0
- data/public/assets/application-759ce4d1ac1e0e3991e6d350c8f98fc5.js +5267 -0
- data/public/assets/application-759ce4d1ac1e0e3991e6d350c8f98fc5.js.gz +0 -0
- data/public/assets/application-f51ea0e777d97f12a8ce84308f31eb57.css +4791 -0
- data/public/assets/application-f51ea0e777d97f12a8ce84308f31eb57.css.gz +0 -0
- data/public/assets/favicon-c7ae857bb9d06de8742ae2d337157e83.ico +0 -0
- data/public/assets/loading-e8e6dd7833131c92a6c3b9c8ccc6a6ac.gif +0 -0
- data/public/assets/manifest-f86249f9779f8f4d7c8fc148e4361b4f.json +1 -0
- data/public/assets/progressbar-82023a146fba2a0f6d925629ed2b09c5.gif +0 -0
- data/public/favicon.ico +0 -0
- data/public/fonts/FontAwesome.otf +0 -0
- data/public/fonts/fontawesome-webfont.eot +0 -0
- data/public/fonts/fontawesome-webfont.ttf +0 -0
- data/public/fonts/fontawesome-webfont.woff +0 -0
- data/public/robots.txt +5 -0
- data/smalruby-editor.gemspec +81 -0
- data/spec/acceptance/readme.md +3 -0
- data/spec/acceptance/standalone/save.feature +32 -0
- data/spec/acceptance/text_editor/base.feature +24 -0
- data/spec/acceptance/text_editor/check.feature +25 -0
- data/spec/acceptance/text_editor/load.feature +81 -0
- data/spec/acceptance/text_editor/save.feature +34 -0
- data/spec/controllers/editor_controller_spec.rb +12 -0
- data/spec/controllers/source_codes_controller_spec.rb +469 -0
- data/spec/fixtures/files/01.rb +57 -0
- data/spec/fixtures/files/favicon.ico +0 -0
- data/spec/helpers/editor_helper_spec.rb +14 -0
- data/spec/lib/smalruby_editor_spec.rb +66 -0
- data/spec/models/source_code_spec.rb +55 -0
- data/spec/spec_helper.rb +156 -0
- data/spec/steps/ace_steps.rb +59 -0
- data/spec/steps/global_variable.rb +39 -0
- data/spec/steps/text_editor_steps.rb +183 -0
- data/spec/support/assets.rb +18 -0
- data/spec/support/capybara.rb +17 -0
- data/spec/support/env.rb +15 -0
- data/spec/turnip_helper.rb +2 -0
- data/vendor/assets/javascripts/.keep +0 -0
- data/vendor/assets/stylesheets/.keep +0 -0
- metadata +407 -0
@@ -0,0 +1,469 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe SourceCodesController do
|
5
|
+
describe 'プログラムが正しいかチェックする (XHR POST check)' do
|
6
|
+
before do
|
7
|
+
params = {
|
8
|
+
source_code: {
|
9
|
+
data: data,
|
10
|
+
}
|
11
|
+
}.with_indifferent_access
|
12
|
+
|
13
|
+
xhr :post, :check, params
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'プログラムが正しい場合' do
|
17
|
+
let(:data) { 'puts "Hello, World!"' }
|
18
|
+
|
19
|
+
it { expect(response).to be_success }
|
20
|
+
|
21
|
+
it do
|
22
|
+
expected = parse_json(SourceCode.new(data: data).check_syntax.to_json)
|
23
|
+
expect(parse_json(response.body)).to eq(expected)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'プログラムが正しくない場合' do
|
28
|
+
let(:data) { 'puts Hello, World!"' }
|
29
|
+
|
30
|
+
it { expect(response).to be_success }
|
31
|
+
|
32
|
+
it do
|
33
|
+
expected = parse_json(SourceCode.new(data: data).check_syntax.to_json)
|
34
|
+
expect(parse_json(response.body)).to eq(expected)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'プログラムを保存する (XHR POST create)' do
|
40
|
+
let(:params) {
|
41
|
+
{
|
42
|
+
source_code: {
|
43
|
+
filename: '01.rb',
|
44
|
+
data: 'puts "Hello, World!"',
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
describe 'レスポンス' do
|
50
|
+
subject {
|
51
|
+
xhr :post, :create, params
|
52
|
+
response
|
53
|
+
}
|
54
|
+
|
55
|
+
it { should be_success }
|
56
|
+
it {
|
57
|
+
ids = SourceCode.all.map(&:id)
|
58
|
+
expect(parse_json(subject.body))
|
59
|
+
.to eq('source_code' => {
|
60
|
+
'id' => SourceCode.find(SourceCode.all.map(&:id) - ids)
|
61
|
+
.first.id
|
62
|
+
})
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'アップロードされたプログラムを保存できる' do
|
67
|
+
expect {
|
68
|
+
xhr :post, :create, params
|
69
|
+
}.to change { SourceCode.count }.by(1)
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'アップロードされたプログラム' do
|
73
|
+
subject {
|
74
|
+
ids = SourceCode.all.map(&:id)
|
75
|
+
xhr :post, :create, params
|
76
|
+
SourceCode.find((SourceCode.all.map(&:id) - ids).first)
|
77
|
+
}
|
78
|
+
|
79
|
+
its(:data) { should eq(params[:source_code][:data]) }
|
80
|
+
its(:filename) { should eq(params[:source_code][:filename]) }
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'session' do
|
84
|
+
before {
|
85
|
+
ids = SourceCode.all.map(&:id)
|
86
|
+
xhr :post, :create, params
|
87
|
+
@created_source_code =
|
88
|
+
SourceCode.find((SourceCode.all.map(&:id) - ids).first)
|
89
|
+
}
|
90
|
+
|
91
|
+
subject { session }
|
92
|
+
|
93
|
+
it '[:source_code][:id]はアップロードしたプログラムのIDである' do
|
94
|
+
expect(subject[:source_code][:id]).to eq(@created_source_code.id)
|
95
|
+
end
|
96
|
+
|
97
|
+
it '[:source_code][:digest]はアップロードしたプログラムのSHA256のハッシュ値である' do
|
98
|
+
expect(subject[:source_code][:digest])
|
99
|
+
.to eq(@created_source_code.digest)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'プログラムをダウンロードしてサーバ上から削除する (DELETE download)' do
|
105
|
+
let(:source_code) {
|
106
|
+
SourceCode.create!(filename: '01.rb', data: 'puts "Hello, World!"')
|
107
|
+
}
|
108
|
+
|
109
|
+
context 'セッションが正しい場合' do
|
110
|
+
let(:_session) {
|
111
|
+
{
|
112
|
+
source_code: {
|
113
|
+
id: source_code.id,
|
114
|
+
digest: source_code.digest,
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
context 'ファイル名が半角英数字の場合' do
|
120
|
+
before do
|
121
|
+
allow(@controller).to receive(:send_data).and_call_original
|
122
|
+
delete :download, {}, _session
|
123
|
+
end
|
124
|
+
|
125
|
+
specify 'プログラムをダウンロードする' do
|
126
|
+
expect(@controller).to have_received(:send_data)
|
127
|
+
.with(source_code.data,
|
128
|
+
filename: source_code.filename,
|
129
|
+
disposition: 'attachment',
|
130
|
+
type: 'text/plain; charset=utf-8')
|
131
|
+
.once
|
132
|
+
end
|
133
|
+
|
134
|
+
specify 'プログラムをサーバ上から削除する' do
|
135
|
+
expect(SourceCode).to have(0).records
|
136
|
+
end
|
137
|
+
|
138
|
+
specify 'セッションから[:source_code]を削除する' do
|
139
|
+
expect(session[:source_code]).to be_nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'ファイル名が日本語の場合' do
|
144
|
+
# rubocop:disable LineLength
|
145
|
+
USER_AGENT = {
|
146
|
+
IE11: 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko',
|
147
|
+
IE10: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Touch)',
|
148
|
+
Chrome20: 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11',
|
149
|
+
Firefox14: 'Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1',
|
150
|
+
}
|
151
|
+
# rubocop:enable LineLength
|
152
|
+
|
153
|
+
let(:source_code) {
|
154
|
+
SourceCode.create!(filename: '日本語.rb', data: 'puts "Hello, World!"')
|
155
|
+
}
|
156
|
+
|
157
|
+
[:IE10, :IE11].each do |browser|
|
158
|
+
context "ブラウザが#{browser}の場合" do
|
159
|
+
before do
|
160
|
+
@request.env['HTTP_USER_AGENT'] = USER_AGENT[browser]
|
161
|
+
allow(@controller).to receive(:send_data).and_call_original
|
162
|
+
delete :download, {}, _session
|
163
|
+
end
|
164
|
+
|
165
|
+
specify 'プログラムをダウンロードする' do
|
166
|
+
expect(@controller).to have_received(:send_data)
|
167
|
+
.with(source_code.data,
|
168
|
+
filename: ERB::Util.url_encode(source_code.filename),
|
169
|
+
disposition: 'attachment',
|
170
|
+
type: 'text/plain; charset=utf-8')
|
171
|
+
.once
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
[:Chrome20, :Firefox14].each do |browser|
|
177
|
+
context "ブラウザが#{browser}の場合" do
|
178
|
+
before do
|
179
|
+
@request.env['HTTP_USER_AGENT'] = USER_AGENT[browser]
|
180
|
+
allow(@controller).to receive(:send_data).and_call_original
|
181
|
+
delete :download, {}, _session
|
182
|
+
end
|
183
|
+
|
184
|
+
specify 'プログラムをダウンロードする' do
|
185
|
+
expect(@controller).to have_received(:send_data)
|
186
|
+
.with(source_code.data,
|
187
|
+
filename: source_code.filename,
|
188
|
+
disposition: 'attachment',
|
189
|
+
type: 'text/plain; charset=utf-8')
|
190
|
+
.once
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'セッションが不正な場合' do
|
198
|
+
shared_examples 'raise exception' do
|
199
|
+
it {
|
200
|
+
expect {
|
201
|
+
delete :download, {}, _session
|
202
|
+
}.to raise_exception
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'セッションに[:source_code]がない場合' do
|
207
|
+
let(:_session) { {} }
|
208
|
+
|
209
|
+
include_examples 'raise exception'
|
210
|
+
end
|
211
|
+
|
212
|
+
context 'セッションに[:source_code][:id]がない場合' do
|
213
|
+
let(:_session) {
|
214
|
+
{
|
215
|
+
source_code: {
|
216
|
+
digest: source_code.digest,
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
include_examples 'raise exception'
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'セッションに[:source_code][:digest]がない場合' do
|
225
|
+
let(:_session) {
|
226
|
+
{
|
227
|
+
source_code: {
|
228
|
+
id: source_code.id,
|
229
|
+
}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
include_examples 'raise exception'
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'セッションの[:source_code][:digest]が不正な場合' do
|
237
|
+
let(:_session) {
|
238
|
+
{
|
239
|
+
source_code: {
|
240
|
+
id: source_code.id,
|
241
|
+
digest: 'invalid_digest',
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
include_examples 'raise exception'
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe 'プログラムをホームディレクトリに保存してサーバ上から削除する' \
|
252
|
+
' (DELETE write)' do
|
253
|
+
let(:source_code) {
|
254
|
+
SourceCode.create!(filename: '01.rb', data: 'puts "Hello, World!"')
|
255
|
+
}
|
256
|
+
let(:params) { {} }
|
257
|
+
let(:_session) {
|
258
|
+
{
|
259
|
+
source_code: {
|
260
|
+
id: source_code.id,
|
261
|
+
digest: source_code.digest,
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
context 'RAILS_ENVがstandaloneの場合', set_standalone_rails_env: true do
|
267
|
+
let(:path) { Pathname("~/#{source_code.filename}").expand_path.to_s }
|
268
|
+
|
269
|
+
context 'セッションが正しい場合' do
|
270
|
+
shared_examples 'success writing' do
|
271
|
+
let(:target_file) {
|
272
|
+
f = double('File')
|
273
|
+
allow(f).to receive(:write)
|
274
|
+
f
|
275
|
+
}
|
276
|
+
|
277
|
+
before do
|
278
|
+
allow(File).to receive(:open).and_yield(target_file)
|
279
|
+
xhr :delete, :write, params, _session
|
280
|
+
end
|
281
|
+
|
282
|
+
specify { expect(response).to be_success }
|
283
|
+
|
284
|
+
specify 'ホームディレクトリにファイルを保存する' do
|
285
|
+
expect(File).to have_received(:open).with(path, 'w').once
|
286
|
+
expect(target_file)
|
287
|
+
.to have_received(:write).with(source_code.data).once
|
288
|
+
end
|
289
|
+
|
290
|
+
specify 'プログラムをサーバ上から削除する' do
|
291
|
+
expect(SourceCode).to have(0).records
|
292
|
+
end
|
293
|
+
|
294
|
+
specify 'セッションから[:source_code]を削除する' do
|
295
|
+
expect(session[:source_code]).to be_nil
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context '同じ名前のファイルが存在しない場合' do
|
300
|
+
before do
|
301
|
+
allow(File).to receive(:exist?).with(path).and_return(false)
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'ファイル名が半角英数字の場合' do
|
305
|
+
include_examples 'success writing'
|
306
|
+
end
|
307
|
+
|
308
|
+
context 'ファイル名が日本語の場合' do
|
309
|
+
let(:source_code) {
|
310
|
+
SourceCode.create!(filename: '日本語でも表現できる.rb',
|
311
|
+
data: 'puts "Hello, World!"')
|
312
|
+
}
|
313
|
+
|
314
|
+
include_examples 'success writing'
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
context '同じ名前のファイルが存在する場合' do
|
319
|
+
before do
|
320
|
+
allow(File).to receive(:exist?).with(path).and_return(true)
|
321
|
+
end
|
322
|
+
|
323
|
+
context '上書き保存モードの場合' do
|
324
|
+
let(:params) { { force: true } }
|
325
|
+
|
326
|
+
include_examples 'success writing'
|
327
|
+
end
|
328
|
+
|
329
|
+
context '上書き保存モードではない場合' do
|
330
|
+
before do
|
331
|
+
xhr :delete, :write, params, _session
|
332
|
+
end
|
333
|
+
|
334
|
+
specify 'プログラムをサーバ上から削除しない' do
|
335
|
+
expect(SourceCode).to have(1).records
|
336
|
+
end
|
337
|
+
|
338
|
+
specify 'セッションから[:source_code]を削除しない' do
|
339
|
+
expect(session[:source_code]).to eq(_session[:source_code])
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context 'セッションが不正な場合' do
|
346
|
+
shared_examples 'raise exception' do
|
347
|
+
it {
|
348
|
+
expect {
|
349
|
+
xhr :delete, :write, params, _session
|
350
|
+
}.to raise_exception
|
351
|
+
}
|
352
|
+
end
|
353
|
+
|
354
|
+
context 'セッションに[:source_code]がない場合' do
|
355
|
+
let(:_session) { {} }
|
356
|
+
|
357
|
+
include_examples 'raise exception'
|
358
|
+
end
|
359
|
+
|
360
|
+
context 'セッションに[:source_code][:id]がない場合' do
|
361
|
+
let(:_session) {
|
362
|
+
{
|
363
|
+
source_code: {
|
364
|
+
digest: source_code.digest,
|
365
|
+
}
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
include_examples 'raise exception'
|
370
|
+
end
|
371
|
+
|
372
|
+
context 'セッションに[:source_code][:digest]がない場合' do
|
373
|
+
let(:_session) {
|
374
|
+
{
|
375
|
+
source_code: {
|
376
|
+
id: source_code.id,
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
include_examples 'raise exception'
|
382
|
+
end
|
383
|
+
|
384
|
+
context 'セッションの[:source_code][:digest]が不正な場合' do
|
385
|
+
let(:_session) {
|
386
|
+
{
|
387
|
+
source_code: {
|
388
|
+
id: source_code.id,
|
389
|
+
digest: 'invalid_digest',
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
include_examples 'raise exception'
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
context 'RAILS_ENVがstandalone以外の場合' do
|
400
|
+
subject do
|
401
|
+
xhr :delete, :write, params, _session
|
402
|
+
end
|
403
|
+
|
404
|
+
it { expect { subject }.to raise_exception }
|
405
|
+
|
406
|
+
it 'プログラムをサーバ上から削除しない' do
|
407
|
+
begin
|
408
|
+
subject
|
409
|
+
rescue
|
410
|
+
expect(SourceCode).to have(1).records
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'セッションから[:source_code]を削除しない' do
|
415
|
+
begin
|
416
|
+
subject
|
417
|
+
rescue
|
418
|
+
expect(session[:source_code]).to eq(_session[:source_code])
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe 'プログラムを読み込む (POST load)' do
|
425
|
+
before do
|
426
|
+
post :load, source_code: { file: load_file }
|
427
|
+
end
|
428
|
+
|
429
|
+
describe '正常系' do
|
430
|
+
let(:load_file) { fixture_file_upload('files/01.rb', 'text/plain') }
|
431
|
+
|
432
|
+
it { expect(response).to be_success }
|
433
|
+
|
434
|
+
it 'アップロードされたプログラムの情報をJSON形式でダウンロードできる' do
|
435
|
+
load_file.rewind
|
436
|
+
expected = {
|
437
|
+
source_code: {
|
438
|
+
filename: load_file.original_filename,
|
439
|
+
type: load_file.content_type,
|
440
|
+
size: load_file.size,
|
441
|
+
data: load_file.read.force_encoding('utf-8'),
|
442
|
+
}
|
443
|
+
}.to_json
|
444
|
+
expect(response.body).to be_json_eql(expected)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
describe '異常系' do
|
449
|
+
context '画像をアップロードした場合' do
|
450
|
+
let(:load_file) {
|
451
|
+
fixture_file_upload('files/favicon.ico', 'application/octet-stream')
|
452
|
+
}
|
453
|
+
|
454
|
+
it { expect(response).to be_success }
|
455
|
+
|
456
|
+
it 'エラーを返す' do
|
457
|
+
info = {
|
458
|
+
filename: load_file.original_filename,
|
459
|
+
error: 'Rubyのプログラムではありません',
|
460
|
+
}
|
461
|
+
info.each do |path, value|
|
462
|
+
expect(response.body)
|
463
|
+
.to include_json(value.to_json).at_path("source_code/#{path}")
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# 画面をクリックして隠れている車を1台探してみよう
|
3
|
+
|
4
|
+
require "smalruby"
|
5
|
+
|
6
|
+
# <プログラム> # <説明>
|
7
|
+
canvas1 = Canvas.new # 背景を用意する
|
8
|
+
car1 = Character.new(x: 0, y: 148, costume: "car3.png", visible: true)
|
9
|
+
# 車を用意する (最初に隠しておく)
|
10
|
+
|
11
|
+
# <プログラム> # <説明>
|
12
|
+
canvas1.on(:start) do # (背景は) 始まったとき
|
13
|
+
draw_font(x: 0, y: 0,
|
14
|
+
string: "画面をクリックして隠れている車を探してね",
|
15
|
+
size: 32) # (0, 0) に (32) の大きさで
|
16
|
+
# 「画面をクリックして隠れている車を探してね」の
|
17
|
+
# 文章を表示する
|
18
|
+
draw_font(x: 0, y: 32,
|
19
|
+
string: "ヒント:線の少し上だよ",
|
20
|
+
size: 24) # (0, 32) に (24) の大きさで
|
21
|
+
# 「ヒント:線の少し上だよ」の
|
22
|
+
# 文章を表示する
|
23
|
+
box_fill(x1: 0, y1: 200,
|
24
|
+
x2: 639, y2: 204,
|
25
|
+
color: "red") # (0, 200)-(639, 204) の四角を
|
26
|
+
# (white) 色で塗りつぶす
|
27
|
+
end
|
28
|
+
|
29
|
+
# <プログラム> # <説明>
|
30
|
+
canvas1.on(:click) do |x, y| # (背景は) クリックしたとき
|
31
|
+
canvas2 = Canvas.new(x: x - 9, y: y - 9, width: 20, height: 20)
|
32
|
+
# (お絵かき) を用意する
|
33
|
+
canvas2.on(:start) do # >> (お絵かきは) 始まったとき
|
34
|
+
circle_fill(x: 9, y: 9, r: 9, color: "white")
|
35
|
+
# >> (9, 9)、半径9の円をwhite色で塗りつぶす
|
36
|
+
sleep(0.5) # >> (0.5) 秒待つ
|
37
|
+
vanish # >> (お絵かきを) 取り除く
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# <プログラム> # <説明>
|
42
|
+
car1.on(:start) do # (車は) プログラムが始まったとき
|
43
|
+
speed = rand(10..20) # (speed) を (5~10までのランダム) にする
|
44
|
+
loop do # ずっと
|
45
|
+
move(speed) # >> (speed) 歩動かす
|
46
|
+
turn_if_reach_wall # >> もし端に着いたら、跳ね返る
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# <プログラム> # <説明>
|
51
|
+
car1.on(:click) do # (車は) クリックしたとき
|
52
|
+
if self.visible == false # もし (隠している) だったら
|
53
|
+
self.visible = true # >> 表示する
|
54
|
+
else # そうでなければ
|
55
|
+
self.visible = false # >> 隠す
|
56
|
+
end
|
57
|
+
end
|
Binary file
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Specs in this file have access to a helper object that includes
|
4
|
+
# the EditorHelper. For example:
|
5
|
+
#
|
6
|
+
# describe EditorHelper do
|
7
|
+
# describe "string concat" do
|
8
|
+
# it "concats two strings with spaces" do
|
9
|
+
# expect(helper.concat_strings("this","that")).to eq("this that")
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
describe EditorHelper do
|
14
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../spec_helper'
|
3
|
+
require 'smalruby_editor'
|
4
|
+
|
5
|
+
describe SmalrubyEditor do
|
6
|
+
describe '.create_home_directory' do
|
7
|
+
before(:all) do
|
8
|
+
@home_dir = Pathname(Dir.tmpdir).join('.smalruby-editor')
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples 'ホームディレクトリを作成する', create_home_directory: true do
|
12
|
+
after(:all) do
|
13
|
+
FileUtils.rm_rf(@home_dir)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'ホームディレクトリを作成する' do
|
17
|
+
expect(@home_dir).to be_directory
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'ホームディレクトリ' do
|
21
|
+
%w(config db log tmp
|
22
|
+
tmp/cache tmp/pids tmp/sessions tmp/sockets).each do |dir|
|
23
|
+
it "#{dir}ディレクトリを作成する" do
|
24
|
+
expect(@home_dir.join(dir)).to be_directory
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'configディレクトリ' do
|
29
|
+
let(:path) { @home_dir.join('config', 'database.yml') }
|
30
|
+
|
31
|
+
it 'database.ymlを作成する' do
|
32
|
+
expect(path).to be_exist
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'database.ymlの内容が正しい' do
|
36
|
+
expect(path.read).to eq(<<-EOS.strip_heredoc)
|
37
|
+
standalone:
|
38
|
+
adapter: sqlite3
|
39
|
+
database: #{@home_dir.join('db', 'standalone.sqlite3')}
|
40
|
+
pool: 5
|
41
|
+
timeout: 5000
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it '戻り値は作成したホームディレクトリである' do
|
49
|
+
expect(SmalrubyEditor.create_home_directory(@home_dir)).to eq(@home_dir)
|
50
|
+
end
|
51
|
+
|
52
|
+
context '引数を指定した場合', create_home_directory: true do
|
53
|
+
before(:all) do
|
54
|
+
SmalrubyEditor.create_home_directory(@home_dir)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '引数を指定しない場合は環境変数SMALRUBY_EDITOR_HOMEに従う',
|
59
|
+
create_home_directory: true do
|
60
|
+
before(:all) do
|
61
|
+
ENV['SMALRUBY_EDITOR_HOME'] = @home_dir.to_s
|
62
|
+
SmalrubyEditor.create_home_directory
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe SourceCode, 'Rubyのソースコードを表現するモデル' do
|
5
|
+
describe 'validation' do
|
6
|
+
describe 'filename' do
|
7
|
+
specify 'ディレクトリセパレータを含むことはできない' do
|
8
|
+
sc = SourceCode.new(filename: '/etc/passwd')
|
9
|
+
expect(sc).not_to be_valid
|
10
|
+
expect(sc.errors[:filename])
|
11
|
+
.to include('includes directory separator(s)')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#check_syntax', 'シンタックスをチェックする' do
|
17
|
+
let(:source_code) {
|
18
|
+
SourceCode.new(data: data)
|
19
|
+
}
|
20
|
+
|
21
|
+
subject { source_code.check_syntax }
|
22
|
+
|
23
|
+
context 'シンタックスが正しい場合' do
|
24
|
+
let(:data) { 'puts "Hello, World!"' }
|
25
|
+
|
26
|
+
it { should be_empty }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'シンタックスが正しくない場合' do
|
30
|
+
let(:data) { 'puts Hello, World!"' }
|
31
|
+
|
32
|
+
it { should_not be_empty }
|
33
|
+
it {
|
34
|
+
should include(row: 1, column: 19,
|
35
|
+
message: 'syntax error, unexpected tSTRING_BEG,' \
|
36
|
+
" expecting keyword_do or '{' or '('")
|
37
|
+
}
|
38
|
+
it {
|
39
|
+
should include(row: 1, column: 0,
|
40
|
+
message: 'unterminated string meets end of file')
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#digest', 'プログラムのハッシュ値を計算する' do
|
46
|
+
let(:data) { 'puts "Hello, World!"' }
|
47
|
+
let(:source_code) {
|
48
|
+
SourceCode.new(data: data)
|
49
|
+
}
|
50
|
+
|
51
|
+
subject { source_code.digest }
|
52
|
+
|
53
|
+
it { should eq(Digest::SHA256.hexdigest(data)) }
|
54
|
+
end
|
55
|
+
end
|