smalruby-editor 0.0.6 → 0.0.7
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 +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +0 -1
- data/README.rdoc +1 -1
- data/app/assets/javascripts/editor.js.coffee.erb +139 -0
- data/app/controllers/source_codes_controller.rb +52 -13
- data/app/models/source_code.rb +7 -0
- data/app/views/editor/index.html.erb +3 -2
- data/bin/smalruby-editor +0 -1
- data/config/database.yml.mysql2 +9 -0
- data/config/database.yml.sqlite3 +6 -0
- data/config/environments/standalone.rb +8 -10
- data/config/initializers/secret_token.rb +6 -1
- data/config/routes.rb +1 -0
- data/lib/smalruby_editor/version.rb +1 -1
- data/lib/tasks/gem.rake +6 -1
- data/lib/tasks/rspec.rake +16 -16
- data/lib/tasks/rubocop.rake +1 -1
- data/spec/acceptance/standalone/save.feature +32 -0
- data/spec/acceptance/text_editor/check.feature +9 -4
- data/spec/acceptance/text_editor/load.feature +9 -2
- data/spec/acceptance/text_editor/save.feature +3 -0
- data/spec/controllers/source_codes_controller_spec.rb +173 -0
- data/spec/lib/smalruby_editor_spec.rb +4 -2
- data/spec/models/source_code_spec.rb +11 -0
- data/spec/spec_helper.rb +35 -7
- data/spec/steps/ace_steps.rb +1 -2
- data/spec/steps/text_editor_steps.rb +27 -4
- data/spec/support/assets.rb +18 -0
- data/spec/support/env.rb +15 -0
- data/spec/turnip_helper.rb +2 -0
- metadata +14 -6
- data/app/assets/javascripts/editor.js.coffee +0 -105
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27f4c696fc7ebd2507f3025d757ac3a956eb3e10
|
4
|
+
data.tar.gz: 70aec400f0cb75231ab0d19b5250eecab9e64ae5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d2a30f76ea5fbed2ffaf37b38c359641ac148d9a9d73e5bd3aff095eb50beff67a25204fad4d5e895604e5cc13345aadc85255fa7004384dbfc22d764380e93
|
7
|
+
data.tar.gz: 50ba103b5055f534b8b816ee4d2805f117ec88a3939265844fab51d2f3c15a5e5b1a73c48a039e5ce8731ff19130c9a94c6de7cb3cafa3e2de011efa7686d8d3
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -0,0 +1,139 @@
|
|
1
|
+
# Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
# All this logic will automatically be available in application.js.
|
3
|
+
# You can use CoffeeScript in this file: http://coffeescript.org/
|
4
|
+
|
5
|
+
changed = false
|
6
|
+
|
7
|
+
successMessage = (title, msg = '', selector = '#messages') ->
|
8
|
+
html = $('<div class="alert alert-success" style="display: none">')
|
9
|
+
.append("<h4><i class=\"icon-star\"></i>#{title}</h4>")
|
10
|
+
.append(msg)
|
11
|
+
$(selector).append(html)
|
12
|
+
html.fadeIn('slow')
|
13
|
+
.delay(3000)
|
14
|
+
.fadeOut('slow')
|
15
|
+
|
16
|
+
errorMessage = (msg, selector = '#messages') ->
|
17
|
+
html = $('<div class="alert alert-error" style="display: none">')
|
18
|
+
.append('<button type="button" class="close" data-dismiss="alert">×</button>')
|
19
|
+
.append('<h4><i class="icon-exclamation-sign"></i>エラー</h4>')
|
20
|
+
.append(msg)
|
21
|
+
$(selector).append(html)
|
22
|
+
html.fadeIn('slow')
|
23
|
+
.delay(10000)
|
24
|
+
.fadeOut('slow')
|
25
|
+
|
26
|
+
$ ->
|
27
|
+
saving = false
|
28
|
+
|
29
|
+
textEditor = ace.edit('text-editor')
|
30
|
+
textEditor.setTheme('ace/theme/github')
|
31
|
+
textEditor.setShowInvisibles(true)
|
32
|
+
|
33
|
+
textEditor.focus()
|
34
|
+
textEditor.gotoLine(0, 0)
|
35
|
+
|
36
|
+
textEditor.on 'change', (e) ->
|
37
|
+
changed = true
|
38
|
+
|
39
|
+
session = textEditor.getSession()
|
40
|
+
session.setMode('ace/mode/ruby')
|
41
|
+
session.setTabSize(2)
|
42
|
+
session.setUseSoftTabs(true)
|
43
|
+
|
44
|
+
$('#check-button').click (e) ->
|
45
|
+
e.preventDefault()
|
46
|
+
$.ajax
|
47
|
+
url: '/source_codes/check'
|
48
|
+
type: 'POST'
|
49
|
+
data:
|
50
|
+
source_code:
|
51
|
+
data: session.getDocument().getValue()
|
52
|
+
dataType: 'json'
|
53
|
+
success: (data, textStatus, jqXHR) ->
|
54
|
+
if data.length == 0
|
55
|
+
successMessage('チェックしました', 'ただし、プログラムを動かすとエラーが見つかるかもしれません。')
|
56
|
+
else
|
57
|
+
for errorInfo in data
|
58
|
+
do (errorInfo) ->
|
59
|
+
msg = "#{errorInfo.row}行"
|
60
|
+
if errorInfo.column > 0
|
61
|
+
msg += "、#{errorInfo.column}文字"
|
62
|
+
errorMessage(msg + ": #{errorInfo.message}")
|
63
|
+
|
64
|
+
$('#save-button').click (e) ->
|
65
|
+
e.preventDefault()
|
66
|
+
filename = $.trim($('#filename').val())
|
67
|
+
if filename.length <= 0
|
68
|
+
errorMessage('セーブする前にプログラムに名前をつけてね!')
|
69
|
+
$('#filename').focus()
|
70
|
+
else
|
71
|
+
afterSave = ->
|
72
|
+
saving = true
|
73
|
+
changed = false
|
74
|
+
successMessage('セーブしました')
|
75
|
+
$.ajax
|
76
|
+
url: '/source_codes/'
|
77
|
+
type: 'POST'
|
78
|
+
data:
|
79
|
+
source_code:
|
80
|
+
filename: filename
|
81
|
+
data: session.getDocument().getValue()
|
82
|
+
dataType: 'json'
|
83
|
+
success: (data, textStatus, jqXHR) ->
|
84
|
+
<% if Rails.env == 'standalone' %>
|
85
|
+
$.ajax
|
86
|
+
url: '/source_codes/write'
|
87
|
+
type: 'DELETE'
|
88
|
+
dataType: 'json'
|
89
|
+
success: (data, textStatus, jqXHR) ->
|
90
|
+
if data.source_code.error && confirm("前に#{filename}という名前でセーブしているけど本当にセーブしますか?\nセーブすると前に作成したプログラムは消えてしまうよ!")
|
91
|
+
$.ajax
|
92
|
+
url: '/source_codes/write'
|
93
|
+
type: 'DELETE'
|
94
|
+
data:
|
95
|
+
force: true
|
96
|
+
dataType: 'json'
|
97
|
+
success: (data, textStatus, jqXHR) ->
|
98
|
+
afterSave()
|
99
|
+
else
|
100
|
+
afterSave()
|
101
|
+
<% else %>
|
102
|
+
afterSave()
|
103
|
+
$('#download-link').click()
|
104
|
+
<% end %>
|
105
|
+
|
106
|
+
$('#filename').keypress (e) ->
|
107
|
+
e = window.event if !e
|
108
|
+
if e.keyCode == 13
|
109
|
+
$('#save-button').click()
|
110
|
+
false
|
111
|
+
else
|
112
|
+
true
|
113
|
+
|
114
|
+
$('#load-button').click (e) ->
|
115
|
+
e.preventDefault()
|
116
|
+
if changed
|
117
|
+
return unless confirm('まだセーブしていないのでロードするとプログラムが消えてしまうよ!\nそれでもロードしますか?')
|
118
|
+
$(@).parent().find('input[name="source_code[file]"]').click()
|
119
|
+
|
120
|
+
$('#file-form').fileupload
|
121
|
+
dataType: 'json'
|
122
|
+
done: (e, data) ->
|
123
|
+
info = data.result.source_code
|
124
|
+
if info.error
|
125
|
+
errorMessage(info.filename + 'は' + info.error)
|
126
|
+
else
|
127
|
+
$('#filename').val(info.filename)
|
128
|
+
session.getDocument().setValue(info.data)
|
129
|
+
textEditor.focus()
|
130
|
+
textEditor.moveCursorTo(0, 0)
|
131
|
+
changed = false
|
132
|
+
successMessage('ロードしました')
|
133
|
+
|
134
|
+
window.onbeforeunload = (event) ->
|
135
|
+
if !saving && session.getDocument().getValue().length > 0
|
136
|
+
return '作成中のプログラムが消えてしまうよ!'
|
137
|
+
else
|
138
|
+
saving = false
|
139
|
+
return
|
@@ -2,33 +2,41 @@
|
|
2
2
|
require 'nkf'
|
3
3
|
|
4
4
|
class SourceCodesController < ApplicationController
|
5
|
+
before_filter :check_whether_standalone, only: :write
|
6
|
+
|
5
7
|
def check
|
6
8
|
render json: SourceCode.new(source_code_params).check_syntax
|
7
9
|
end
|
8
10
|
|
9
11
|
def create
|
10
|
-
|
12
|
+
sc = SourceCode.create!(source_code_params)
|
11
13
|
session[:source_code] = {
|
12
|
-
id:
|
13
|
-
digest:
|
14
|
+
id: sc.id,
|
15
|
+
digest: sc.digest,
|
14
16
|
}
|
15
|
-
render json: { source_code: { id:
|
17
|
+
render json: { source_code: { id: sc.id } }
|
16
18
|
end
|
17
19
|
|
18
20
|
def download
|
19
|
-
source_code = SourceCode.find(session[:source_code][:id])
|
20
|
-
unless source_code.digest == session[:source_code][:digest]
|
21
|
-
fail ActiveRecord::RecordNotFound
|
22
|
-
end
|
23
|
-
|
24
21
|
send_data(source_code.data,
|
25
|
-
filename:
|
22
|
+
filename: url_encode_filename(source_code.filename),
|
26
23
|
disposition: 'attachment',
|
27
24
|
type: 'text/plain; charset=utf-8')
|
28
25
|
|
29
|
-
source_code
|
26
|
+
destroy_source_code_and_delete_session(source_code)
|
27
|
+
end
|
30
28
|
|
31
|
-
|
29
|
+
def write
|
30
|
+
res = { source_code: { filename: source_code.filename } }
|
31
|
+
|
32
|
+
write_source_code(source_code)
|
33
|
+
|
34
|
+
destroy_source_code_and_delete_session(source_code)
|
35
|
+
|
36
|
+
render json: res
|
37
|
+
rescue => e
|
38
|
+
res[:source_code][:error] = e.message
|
39
|
+
render json: res
|
32
40
|
end
|
33
41
|
|
34
42
|
def load
|
@@ -45,6 +53,12 @@ class SourceCodesController < ApplicationController
|
|
45
53
|
|
46
54
|
private
|
47
55
|
|
56
|
+
def check_whether_standalone
|
57
|
+
unless Rails.env == 'standalone'
|
58
|
+
fail "#{self.class.name}##{action_name}はstandaloneモードのみの機能です"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
48
62
|
def source_code_params
|
49
63
|
params.require(:source_code).permit(:data, :filename)
|
50
64
|
end
|
@@ -57,11 +71,36 @@ class SourceCodesController < ApplicationController
|
|
57
71
|
}
|
58
72
|
end
|
59
73
|
|
60
|
-
def
|
74
|
+
def url_encode_filename(filename)
|
61
75
|
if request.env['HTTP_USER_AGENT'] =~ /MSIE|Trident/
|
62
76
|
return ERB::Util.url_encode(filename)
|
63
77
|
else
|
64
78
|
filename
|
65
79
|
end
|
66
80
|
end
|
81
|
+
|
82
|
+
def source_code
|
83
|
+
return @source_code if @source_code
|
84
|
+
sc = SourceCode.find(session[:source_code][:id])
|
85
|
+
unless sc.digest == session[:source_code][:digest]
|
86
|
+
fail ActiveRecord::RecordNotFound
|
87
|
+
end
|
88
|
+
@source_code = sc
|
89
|
+
end
|
90
|
+
|
91
|
+
def write_source_code(source_code)
|
92
|
+
path = Pathname("~/#{source_code.filename}").expand_path.to_s
|
93
|
+
|
94
|
+
fail 'すでに同じ名前のプログラムがあります' if File.exist?(path) && params[:force].blank?
|
95
|
+
|
96
|
+
File.open(path, 'w') do |f|
|
97
|
+
f.write(source_code.data)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def destroy_source_code_and_delete_session(source_code)
|
102
|
+
source_code.destroy
|
103
|
+
|
104
|
+
session[:source_code] = nil
|
105
|
+
end
|
67
106
|
end
|
data/app/models/source_code.rb
CHANGED
@@ -7,6 +7,7 @@ require 'digest/sha2'
|
|
7
7
|
# ソースコードを表現するモデル
|
8
8
|
class SourceCode < ActiveRecord::Base
|
9
9
|
validates :filename, presence: true
|
10
|
+
validate :validate_filename
|
10
11
|
validates :data, presence: true, allow_blank: true
|
11
12
|
|
12
13
|
# シンタックスをチェックする
|
@@ -39,4 +40,10 @@ class SourceCode < ActiveRecord::Base
|
|
39
40
|
RbConfig::CONFIG['RUBY_INSTALL_NAME'])
|
40
41
|
Open3.capture3("#{ruby_cmd} -c #{path}")
|
41
42
|
end
|
43
|
+
|
44
|
+
def validate_filename
|
45
|
+
if File.basename(filename) != filename
|
46
|
+
errors.add(:filename, 'includes directory separator(s)')
|
47
|
+
end
|
48
|
+
end
|
42
49
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
<div class="navbar navbar-inverse">
|
2
2
|
<div class="navbar-inner">
|
3
3
|
<ul class="nav">
|
4
|
-
<li class="active"><a id="ruby-tab" href="#">Ruby</a></li>
|
4
|
+
<li class="active"><a id="ruby-tab" href="#" onclick="window.event.preventDefault(); return false;">Ruby</a></li>
|
5
5
|
</ul>
|
6
6
|
|
7
7
|
<%= form_tag(source_codes_load_path, id: "file-form", class: "navbar-form pull-right", method: "post", multipart: true) do %>
|
8
8
|
<button id="check-button" type="button" class="btn btn-primary">チェック</button>
|
9
9
|
<input id="filename" type="text" class="span4" placeholder="プログラムの名前を入れてね(例:01.rb)">
|
10
10
|
<button id="save-button" type="button" class="btn btn-primary">セーブ</button>
|
11
|
+
<% unless Rails.env == 'standalone' %>
|
11
12
|
<%= link_to '', source_codes_download_path, id: 'download-link', style: 'display: none', 'data-method' => 'delete' %>
|
13
|
+
<% end %>
|
12
14
|
<button id="load-button" class="btn btn-primary">ロード</button>
|
13
15
|
<input id="load-file" type="file" name="source_code[file]" style="display: none">
|
14
16
|
<% end %>
|
@@ -19,4 +21,3 @@
|
|
19
21
|
</div>
|
20
22
|
|
21
23
|
<div id="text-editor"></div>
|
22
|
-
|
data/bin/smalruby-editor
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
require 'pathname'
|
5
5
|
|
6
6
|
ENV['RAILS_ENV'] = 'standalone'
|
7
|
-
ENV['SECRET_KEY_BASE'] ||= 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
8
7
|
ENV['SMALRUBY_EDITOR_HOME'] ||= Pathname('~/.smalruby-editor').expand_path.to_s
|
9
8
|
|
10
9
|
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
data/config/database.yml.mysql2
CHANGED
data/config/database.yml.sqlite3
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
require_relative 'production'
|
2
2
|
|
3
3
|
SmalrubyEditor::Application.configure do
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
home_dir = SmalrubyEditor.create_home_directory
|
4
|
+
if ENV['SMALRUBY_EDITOR_HOME'].present?
|
5
|
+
home_dir = SmalrubyEditor.create_home_directory
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
config.paths.add('config/database',
|
8
|
+
with: home_dir.join('config/database.yml'))
|
9
|
+
config.paths.add('log', with: home_dir.join("log/#{Rails.env}.log"))
|
10
|
+
config.paths.add('tmp', with: home_dir.join('tmp'))
|
11
|
+
config.paths.add('tmp/cache', with: home_dir.join('tmp/cache'))
|
12
|
+
end
|
15
13
|
|
16
14
|
config.serve_static_assets = true
|
17
15
|
config.log_level = :warn
|
@@ -9,4 +9,9 @@
|
|
9
9
|
|
10
10
|
# Make sure your secret_key_base is kept private
|
11
11
|
# if you're sharing your code publicly.
|
12
|
-
|
12
|
+
if Rails.env == 'production'
|
13
|
+
secret_key_base = ENV['SECRET_KEY_BASE']
|
14
|
+
else
|
15
|
+
secret_key_base = '123456789012345678901234567890'
|
16
|
+
end
|
17
|
+
SmalrubyEditor::Application.config.secret_key_base = secret_key_base
|
data/config/routes.rb
CHANGED
data/lib/tasks/gem.rake
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
|
3
|
-
task '
|
3
|
+
task 'assets:precompile:standalone' do
|
4
|
+
Rails.env = ENV['RAILS_ENV'] = 'standalone'
|
5
|
+
Rake::Task['assets:precompile'].invoke
|
6
|
+
end
|
7
|
+
|
8
|
+
task 'build' => ['assets:clobber', 'assets:precompile:standalone']
|
4
9
|
|
5
10
|
|
data/lib/tasks/rspec.rake
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
begin
|
2
|
-
if defined? RSpec # otherwise fails on non-live environments
|
3
|
-
task(:spec).clear
|
4
|
-
desc "Run all specs/features in spec directory"
|
5
|
-
RSpec::Core::RakeTask.new(:spec => 'db:test:prepare') do |t|
|
6
|
-
t.pattern = './spec/{,**/}*{_spec.rb,.feature}'
|
7
|
-
end
|
8
|
-
|
9
|
-
namespace :spec do
|
10
|
-
desc "Run the code examples in spec/acceptance"
|
11
|
-
RSpec::Core::RakeTask.new(:acceptance => 'db:test:prepare') do |t|
|
12
|
-
t.pattern = './spec/acceptance/{,**/}*.feature'
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
1
|
+
begin
|
2
|
+
if defined? RSpec # otherwise fails on non-live environments
|
3
|
+
task(:spec).clear
|
4
|
+
desc "Run all specs/features in spec directory"
|
5
|
+
RSpec::Core::RakeTask.new(:spec => 'db:test:prepare') do |t|
|
6
|
+
t.pattern = './spec/{,**/}*{_spec.rb,.feature}'
|
7
|
+
end
|
8
|
+
|
9
|
+
namespace :spec do
|
10
|
+
desc "Run the code examples in spec/acceptance"
|
11
|
+
RSpec::Core::RakeTask.new(:acceptance => 'db:test:prepare') do |t|
|
12
|
+
t.pattern = './spec/acceptance/{,**/}*.feature'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/tasks/rubocop.rake
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# language: ja
|
3
|
+
@javascript
|
4
|
+
@standalone
|
5
|
+
機能: Save - プログラムのセーブ(standaloneモード)
|
6
|
+
シナリオ: セーブボタンを押してローカルマシンにプログラムを保存できる
|
7
|
+
前提 "エディタ" 画面を表示する
|
8
|
+
かつ テキストエディタに "puts 'Hello, World!'" を入力済みである
|
9
|
+
かつ プログラムの名前に "01.rb" を指定する
|
10
|
+
|
11
|
+
もし "セーブボタン" をクリックする
|
12
|
+
かつ JavaScriptによるリクエストが終わるまで待つ
|
13
|
+
|
14
|
+
ならば ホームディレクトリに "01.rb" が存在すること
|
15
|
+
かつ ホームディレクトリの "01.rb" の内容が "puts 'Hello, World!'" であること
|
16
|
+
かつ "メッセージ" に "セーブしました" を含むこと
|
17
|
+
|
18
|
+
シナリオ: ローカルマシンに同じ名前のプログラムがある状態でセーブボタンを押す
|
19
|
+
前提 "エディタ" 画面を表示する
|
20
|
+
かつ ホームディレクトリに "puts 'Hello, World!'" という内容の "01.rb" が存在する
|
21
|
+
かつ テキストエディタに "n = 0" を入力済みである
|
22
|
+
かつ プログラムの名前に "01.rb" を指定する
|
23
|
+
|
24
|
+
もし "セーブボタン" をクリックする
|
25
|
+
かつ JavaScriptによるリクエストが終わるまで待つ
|
26
|
+
|
27
|
+
ならば 確認メッセージ "前に01.rbという名前でセーブしているけど本当にセーブしますか?\nセーブすると前に作成したプログラムは消えてしまうよ!" を表示すること
|
28
|
+
かつ ホームディレクトリの "01.rb" の内容が "puts 'Hello, World!'" であること
|
29
|
+
|
30
|
+
もし JavaScriptによるリクエストが終わるまで待つ
|
31
|
+
|
32
|
+
ならば "メッセージ" に "セーブしました" を含むこと
|
@@ -2,19 +2,24 @@
|
|
2
2
|
# language: ja
|
3
3
|
@javascript
|
4
4
|
機能: Check - プログラムのエラーチェック
|
5
|
-
シナリオ:
|
5
|
+
シナリオ: チェックボタンを押してプログラムにシンタックスエラーがないいことをチェックできる
|
6
6
|
前提 "エディタ" 画面を表示する
|
7
7
|
かつ テキストエディタに "puts 'Hello, World!'" を入力済みである
|
8
8
|
|
9
9
|
もし "チェックボタン" をクリックする
|
10
10
|
かつ JavaScriptによるリクエストが終わるまで待つ
|
11
11
|
|
12
|
-
ならば "メッセージ" に "
|
12
|
+
ならば "メッセージ" に "チェックしました" を含むこと
|
13
|
+
かつ "メッセージ" に "ただし、プログラムを動かすとエラーが見つかるかもしれません。" を含むこと
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
シナリオ: チェックボタンを押してプログラムにシンタックスエラーがあることをチェックできる
|
16
|
+
前提 "エディタ" 画面を表示する
|
17
|
+
かつ テキストエディタに "puts Hello, World!'" を入力済みである
|
18
|
+
|
19
|
+
もし "チェックボタン" をクリックする
|
16
20
|
かつ JavaScriptによるリクエストが終わるまで待つ
|
17
21
|
|
18
22
|
ならば "メッセージ" に "エラー" を含むこと
|
19
23
|
かつ "メッセージ" に "1行、19文字: syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '('" を含むこと
|
20
24
|
かつ "メッセージ" に "1行: unterminated string meets end of file" を含むこと
|
25
|
+
かつ "メッセージ" に "チェックしました" を含まないこと
|
@@ -10,6 +10,9 @@
|
|
10
10
|
|
11
11
|
ならば テキストエディタに "files/01.rb" を読み込むこと
|
12
12
|
かつ "プログラム名の入力欄" は "01.rb" であること
|
13
|
+
かつ テキストエディタの 0 行目の 0 文字目にカーソルがあること
|
14
|
+
かつ テキストエディタにフォーカスがあること
|
15
|
+
かつ "メッセージ" に "ロードしました" を含むこと
|
13
16
|
|
14
17
|
シナリオ: プログラムを入力済み状態でプログラムを読み込む
|
15
18
|
前提 "エディタ" 画面を表示する
|
@@ -20,6 +23,9 @@
|
|
20
23
|
|
21
24
|
ならば テキストエディタに "files/01.rb" を読み込むこと
|
22
25
|
かつ "プログラム名の入力欄" は "01.rb" であること
|
26
|
+
かつ テキストエディタの 0 行目の 0 文字目にカーソルがあること
|
27
|
+
かつ テキストエディタにフォーカスがあること
|
28
|
+
かつ "メッセージ" に "ロードしました" を含むこと
|
23
29
|
|
24
30
|
シナリオ: 間違って画像を読み込もうとする
|
25
31
|
前提 "エディタ" 画面を表示する
|
@@ -30,6 +36,7 @@
|
|
30
36
|
ならば テキストエディタのプログラムは "" であること
|
31
37
|
かつ "プログラム名の入力欄" は "" であること
|
32
38
|
かつ "メッセージ" に "favicon.icoはRubyのプログラムではありません" を含むこと
|
39
|
+
かつ "メッセージ" に "ロードしました" を含まないこと
|
33
40
|
|
34
41
|
シナリオ: プログラムを修正後にロードボタンを押す
|
35
42
|
前提 "エディタ" 画面を表示する
|
@@ -37,7 +44,7 @@
|
|
37
44
|
|
38
45
|
もし "ロードボタン" をクリックする
|
39
46
|
|
40
|
-
ならば 確認メッセージ "
|
47
|
+
ならば 確認メッセージ "まだセーブしていないのでロードするとプログラムが消えてしまうよ!\nそれでもロードしますか?" を表示すること
|
41
48
|
|
42
49
|
シナリオ: プログラムを修正後にセーブしてからロードボタンを押す
|
43
50
|
前提 "エディタ" 画面を表示する
|
@@ -71,4 +78,4 @@
|
|
71
78
|
|
72
79
|
もし "ロードボタン" をクリックする
|
73
80
|
|
74
|
-
ならば 確認メッセージ "
|
81
|
+
ならば 確認メッセージ "まだセーブしていないのでロードするとプログラムが消えてしまうよ!\nそれでもロードしますか?" を表示すること
|
@@ -11,6 +11,7 @@
|
|
11
11
|
かつ JavaScriptによるリクエストが終わるまで待つ
|
12
12
|
|
13
13
|
ならば "01.rb" をダウンロードすること
|
14
|
+
かつ "メッセージ" に "セーブしました" を含むこと
|
14
15
|
|
15
16
|
シナリオ: 日本語のファイル名でプログラムを保存できる
|
16
17
|
前提 "エディタ" 画面を表示する
|
@@ -21,6 +22,7 @@
|
|
21
22
|
かつ JavaScriptによるリクエストが終わるまで待つ
|
22
23
|
|
23
24
|
ならば "日本語.rb" をダウンロードすること
|
25
|
+
かつ "メッセージ" に "セーブしました" を含むこと
|
24
26
|
|
25
27
|
シナリオ: ファイル名を入力せずにセーブボタンを押す
|
26
28
|
前提 "エディタ" 画面を表示する
|
@@ -29,3 +31,4 @@
|
|
29
31
|
|
30
32
|
ならば ダウンロードしないこと
|
31
33
|
かつ "プログラム名の入力欄" にフォーカスがあること
|
34
|
+
かつ "メッセージ" に "セーブする前にプログラムに名前をつけてね!" を含むこと
|
@@ -248,6 +248,179 @@ describe SourceCodesController do
|
|
248
248
|
end
|
249
249
|
end
|
250
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
|
+
|
251
424
|
describe 'プログラムを読み込む (POST load)' do
|
252
425
|
before do
|
253
426
|
post :load, source_code: { file: load_file }
|
@@ -18,7 +18,8 @@ describe SmalrubyEditor do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'ホームディレクトリ' do
|
21
|
-
%w(config db log tmp
|
21
|
+
%w(config db log tmp
|
22
|
+
tmp/cache tmp/pids tmp/sessions tmp/sockets).each do |dir|
|
22
23
|
it "#{dir}ディレクトリを作成する" do
|
23
24
|
expect(@home_dir.join(dir)).to be_directory
|
24
25
|
end
|
@@ -54,7 +55,8 @@ describe SmalrubyEditor do
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
57
|
-
describe '引数を指定しない場合は環境変数SMALRUBY_EDITOR_HOMEに従う',
|
58
|
+
describe '引数を指定しない場合は環境変数SMALRUBY_EDITOR_HOMEに従う',
|
59
|
+
create_home_directory: true do
|
58
60
|
before(:all) do
|
59
61
|
ENV['SMALRUBY_EDITOR_HOME'] = @home_dir.to_s
|
60
62
|
SmalrubyEditor.create_home_directory
|
@@ -2,6 +2,17 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
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
|
+
|
5
16
|
describe '#check_syntax', 'シンタックスをチェックする' do
|
6
17
|
let(:source_code) {
|
7
18
|
SourceCode.new(data: data)
|
data/spec/spec_helper.rb
CHANGED
@@ -24,9 +24,6 @@ Spork.prefork do
|
|
24
24
|
# in spec/support/ and its subdirectories.
|
25
25
|
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
|
26
26
|
|
27
|
-
load 'spec/steps/global_variable.rb', true
|
28
|
-
Dir.glob('spec/steps/**/*_steps.rb') { |f| load f, true }
|
29
|
-
|
30
27
|
# Checks for pending migrations before tests are run.
|
31
28
|
# If you are not using ActiveRecord, you can remove this line.
|
32
29
|
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
@@ -48,7 +45,7 @@ Spork.prefork do
|
|
48
45
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
49
46
|
# examples within a transaction, remove the following line or assign false
|
50
47
|
# instead of true.
|
51
|
-
config.use_transactional_fixtures =
|
48
|
+
config.use_transactional_fixtures = false
|
52
49
|
|
53
50
|
# If true, the base class of anonymous controllers will be inferred
|
54
51
|
# automatically. This will be the default behavior in future versions of
|
@@ -106,9 +103,40 @@ Spork.prefork do
|
|
106
103
|
|
107
104
|
config.after(javascript: true) do
|
108
105
|
page.execute_script('window.onbeforeunload = null')
|
109
|
-
if selenium?
|
110
|
-
|
111
|
-
|
106
|
+
FileUtils.rm_rf(downloads_dir) if selenium?
|
107
|
+
end
|
108
|
+
|
109
|
+
config.before(:all, javascript: true, standalone: true) do
|
110
|
+
expire_assets_cache
|
111
|
+
end
|
112
|
+
|
113
|
+
config.after(:all, javascript: true, standalone: true) do
|
114
|
+
expire_assets_cache
|
115
|
+
end
|
116
|
+
|
117
|
+
config.before(javascript: true, standalone: true) do
|
118
|
+
page.driver.restart
|
119
|
+
|
120
|
+
@_rails_env = Rails.env
|
121
|
+
Rails.env = ENV['RAILS_ENV'] = 'standalone'
|
122
|
+
@_home = ENV['HOME']
|
123
|
+
@_tmpdir = ENV['HOME'] = Dir.mktmpdir('smalruby-')
|
124
|
+
end
|
125
|
+
|
126
|
+
config.after(javascript: true, standalone: true) do
|
127
|
+
FileUtils.remove_entry_secure(@_tmpdir)
|
128
|
+
ENV['HOME'] = @_home
|
129
|
+
Rails.env = ENV['RAILS_ENV'] = @_rails_env
|
130
|
+
|
131
|
+
page.driver.restart
|
132
|
+
end
|
133
|
+
|
134
|
+
config.before :suite do
|
135
|
+
DatabaseRewinder.clean_all
|
136
|
+
end
|
137
|
+
|
138
|
+
config.after :each do
|
139
|
+
DatabaseRewinder.clean
|
112
140
|
end
|
113
141
|
end
|
114
142
|
end
|
data/spec/steps/ace_steps.rb
CHANGED
@@ -4,8 +4,7 @@ text_editor = 'テキストエディタ'
|
|
4
4
|
|
5
5
|
step 'テキストエディタにフォーカスがあること' do
|
6
6
|
expect(page.evaluate_script(<<-JS)).to be_true
|
7
|
-
|
8
|
-
document.activeElement
|
7
|
+
ace.edit('#{NAME_INFO[text_editor][:id]}').isFocused()
|
9
8
|
JS
|
10
9
|
end
|
11
10
|
|
@@ -37,12 +37,10 @@ step 'ダウンロードが完了するまで待つ' do
|
|
37
37
|
if poltergeist?
|
38
38
|
until page.response_headers['Content-Disposition'] ||
|
39
39
|
(start_time + 5.seconds) < Time.now
|
40
|
-
sleep
|
40
|
+
sleep(1)
|
41
41
|
end
|
42
42
|
elsif selenium?
|
43
|
-
until downloads_dir.exist? || (start_time + 5.seconds) < Time.now
|
44
|
-
sleep 1
|
45
|
-
end
|
43
|
+
sleep(1) until downloads_dir.exist? || (start_time + 5.seconds) < Time.now
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
@@ -66,6 +64,12 @@ step 'ダウンロードしないこと' do
|
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
67
|
+
step ':name にフォーカスを移す' do |name|
|
68
|
+
page.execute_script(<<-JS)
|
69
|
+
$('#{NAME_INFO[name][:selector]}').focus()
|
70
|
+
JS
|
71
|
+
end
|
72
|
+
|
69
73
|
step ':name にフォーカスがあること' do |name|
|
70
74
|
# HACK: 現在のPhantomJSでは$(':focus')は動作しない
|
71
75
|
# https://github.com/netzpirat/guard-jasmine/issues/48
|
@@ -75,6 +79,8 @@ step ':name にフォーカスがあること' do |name|
|
|
75
79
|
end
|
76
80
|
|
77
81
|
step ':filename をロードする' do |filename|
|
82
|
+
step '"ロードボタン" にフォーカスを移す'
|
83
|
+
|
78
84
|
# HACK: input#load-file[type="file"]は非表示要素であるため、.show()し
|
79
85
|
# ないと見つけられずattach_fileが失敗する
|
80
86
|
page.execute_script("$('#load-file').show()")
|
@@ -123,6 +129,7 @@ step '警告ダイアログの :name ボタンをクリックする' do |name|
|
|
123
129
|
end
|
124
130
|
|
125
131
|
step '確認メッセージ :message を表示すること' do |message|
|
132
|
+
message.gsub!('\n', "\n")
|
126
133
|
if poltergeist?
|
127
134
|
actual = page.evaluate_script('window.confirmMsg')
|
128
135
|
page.execute_script('window.confirmMsg = null')
|
@@ -158,3 +165,19 @@ step '実際にはファイルをロードしないようにしておく' do
|
|
158
165
|
JS
|
159
166
|
end
|
160
167
|
end
|
168
|
+
|
169
|
+
step 'ホームディレクトリに :program という内容の :filename が存在する' do |program, filename|
|
170
|
+
File.open(Pathname("~/#{filename}").expand_path, 'w') do |f|
|
171
|
+
f.write(program)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
step 'ホームディレクトリに :filename が存在すること' do |filename|
|
176
|
+
path = Pathname("~/#{filename}").expand_path
|
177
|
+
expect(path).to be_exist
|
178
|
+
end
|
179
|
+
|
180
|
+
step 'ホームディレクトリの :filename の内容が :program であること' do |filename, program|
|
181
|
+
path = Pathname("~/#{filename}").expand_path
|
182
|
+
expect(path.read).to eq(program)
|
183
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# assetsのキャッシュを削除する
|
4
|
+
#
|
5
|
+
# ただし、このメソッドを呼び出した後で page.driver.restart を実行しなけ
|
6
|
+
# ればブラウザ側のキャッシュが有効になったままとなる。
|
7
|
+
def expire_assets_cache
|
8
|
+
env = Rails.application.assets
|
9
|
+
if Rails.application.config.cache_classes
|
10
|
+
env.instance_variable_set('@assets', {})
|
11
|
+
env.instance_variable_set('@digests', {})
|
12
|
+
env = env.instance_variable_get('@environment')
|
13
|
+
end
|
14
|
+
env.send(:expire_index!)
|
15
|
+
Dir.glob(Rails.root.join('tmp/cache/assets/test/sprockets/*')) { |f|
|
16
|
+
FileUtils.remove_entry_secure(f)
|
17
|
+
}
|
18
|
+
end
|
data/spec/support/env.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
# Rails.envをstandaloneにする
|
6
|
+
shared_context 'set standalone rails env', set_standalone_rails_env: true do
|
7
|
+
before do
|
8
|
+
@_rails_env = Rails.env
|
9
|
+
Rails.env = ENV['RAILS_ENV'] = 'standalone'
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Rails.env = ENV['RAILS_ENV'] = @_rails_env
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smalruby-editor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kouji Takao
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -246,7 +246,7 @@ files:
|
|
246
246
|
- app/assets/images/.keep
|
247
247
|
- app/assets/images/favicon.ico
|
248
248
|
- app/assets/javascripts/application.js
|
249
|
-
- app/assets/javascripts/editor.js.coffee
|
249
|
+
- app/assets/javascripts/editor.js.coffee.erb
|
250
250
|
- app/assets/stylesheets/application.css
|
251
251
|
- app/assets/stylesheets/editor.css.scss
|
252
252
|
- app/assets/stylesheets/flatstrap-custom.css.scss
|
@@ -310,6 +310,7 @@ files:
|
|
310
310
|
- public/robots.txt
|
311
311
|
- smalruby-editor.gemspec
|
312
312
|
- spec/acceptance/readme.md
|
313
|
+
- spec/acceptance/standalone/save.feature
|
313
314
|
- spec/acceptance/text_editor/base.feature
|
314
315
|
- spec/acceptance/text_editor/check.feature
|
315
316
|
- spec/acceptance/text_editor/load.feature
|
@@ -325,16 +326,19 @@ files:
|
|
325
326
|
- spec/steps/ace_steps.rb
|
326
327
|
- spec/steps/global_variable.rb
|
327
328
|
- spec/steps/text_editor_steps.rb
|
329
|
+
- spec/support/assets.rb
|
328
330
|
- spec/support/capybara.rb
|
331
|
+
- spec/support/env.rb
|
332
|
+
- spec/turnip_helper.rb
|
329
333
|
- vendor/assets/javascripts/.keep
|
330
334
|
- vendor/assets/stylesheets/.keep
|
331
|
-
- public/assets/application-
|
332
|
-
- public/assets/application-
|
335
|
+
- public/assets/application-759ce4d1ac1e0e3991e6d350c8f98fc5.js
|
336
|
+
- public/assets/application-759ce4d1ac1e0e3991e6d350c8f98fc5.js.gz
|
333
337
|
- public/assets/application-f51ea0e777d97f12a8ce84308f31eb57.css
|
334
338
|
- public/assets/application-f51ea0e777d97f12a8ce84308f31eb57.css.gz
|
335
339
|
- public/assets/favicon-c7ae857bb9d06de8742ae2d337157e83.ico
|
336
340
|
- public/assets/loading-e8e6dd7833131c92a6c3b9c8ccc6a6ac.gif
|
337
|
-
- public/assets/manifest-
|
341
|
+
- public/assets/manifest-3e334cebc159781a2b475049ad366f6a.json
|
338
342
|
- public/assets/progressbar-82023a146fba2a0f6d925629ed2b09c5.gif
|
339
343
|
homepage: https://github.com/smalruby/smalruby-editor
|
340
344
|
licenses:
|
@@ -395,6 +399,7 @@ specification_version: 4
|
|
395
399
|
summary: A visual programming editor.
|
396
400
|
test_files:
|
397
401
|
- spec/acceptance/readme.md
|
402
|
+
- spec/acceptance/standalone/save.feature
|
398
403
|
- spec/acceptance/text_editor/base.feature
|
399
404
|
- spec/acceptance/text_editor/check.feature
|
400
405
|
- spec/acceptance/text_editor/load.feature
|
@@ -410,4 +415,7 @@ test_files:
|
|
410
415
|
- spec/steps/ace_steps.rb
|
411
416
|
- spec/steps/global_variable.rb
|
412
417
|
- spec/steps/text_editor_steps.rb
|
418
|
+
- spec/support/assets.rb
|
413
419
|
- spec/support/capybara.rb
|
420
|
+
- spec/support/env.rb
|
421
|
+
- spec/turnip_helper.rb
|
@@ -1,105 +0,0 @@
|
|
1
|
-
# Place all the behaviors and hooks related to the matching controller here.
|
2
|
-
# All this logic will automatically be available in application.js.
|
3
|
-
# You can use CoffeeScript in this file: http://coffeescript.org/
|
4
|
-
|
5
|
-
changed = false
|
6
|
-
|
7
|
-
$ ->
|
8
|
-
saving = false
|
9
|
-
|
10
|
-
textEditor = ace.edit('text-editor')
|
11
|
-
textEditor.setTheme('ace/theme/github')
|
12
|
-
textEditor.setShowInvisibles(true)
|
13
|
-
|
14
|
-
textEditor.focus()
|
15
|
-
textEditor.gotoLine(0, 0)
|
16
|
-
|
17
|
-
textEditor.on('change', (e) ->
|
18
|
-
changed = true
|
19
|
-
)
|
20
|
-
|
21
|
-
session = textEditor.getSession()
|
22
|
-
session.setMode('ace/mode/ruby')
|
23
|
-
session.setTabSize(2)
|
24
|
-
session.setUseSoftTabs(true)
|
25
|
-
|
26
|
-
# FIXME: エディタの切り替え機能を実装するときに以下の処理を削除する。
|
27
|
-
# なお、navbarの中のリンクの見た目をよくするためにa要素を使っているのだが、
|
28
|
-
# デフォルトではRubyをクリックするとリンク先に遷移してしまう。そこでリンク
|
29
|
-
# をクリックしてもリンク先に遷移しないようにしている。
|
30
|
-
$('ul.nav li a').click (e) ->
|
31
|
-
e.preventDefault()
|
32
|
-
false
|
33
|
-
|
34
|
-
$('#check-button').click (e) ->
|
35
|
-
e.preventDefault()
|
36
|
-
data =
|
37
|
-
source_code:
|
38
|
-
data: session.getDocument().getValue()
|
39
|
-
success = (data, textStatus, jqXHR) ->
|
40
|
-
for errorInfo in data
|
41
|
-
do (errorInfo) ->
|
42
|
-
msg = $('<div class="alert alert-error" style="display: none">')
|
43
|
-
.append('<button type="button" class="close" data-dismiss="alert">×</button>')
|
44
|
-
.append('<h4><i class="icon-exclamation-sign"></i>エラー</h4>')
|
45
|
-
.append("#{errorInfo.row}行")
|
46
|
-
if errorInfo.column > 0
|
47
|
-
msg.append("、#{errorInfo.column}文字")
|
48
|
-
msg.append(": #{errorInfo.message}")
|
49
|
-
$('#messages').append(msg)
|
50
|
-
msg.fadeIn('slow')
|
51
|
-
$.post('/source_codes/check', data, success, 'json')
|
52
|
-
|
53
|
-
$('#save-button').click (e) ->
|
54
|
-
e.preventDefault()
|
55
|
-
filename = $.trim($('#filename').val())
|
56
|
-
if filename.length <= 0
|
57
|
-
$('#filename').focus()
|
58
|
-
else
|
59
|
-
data =
|
60
|
-
source_code:
|
61
|
-
filename: filename
|
62
|
-
data: session.getDocument().getValue()
|
63
|
-
success = (data, textStatus, jqXHR) ->
|
64
|
-
saving = true
|
65
|
-
changed = false
|
66
|
-
$('#download-link').click()
|
67
|
-
$.post('/source_codes/', data, success, 'json')
|
68
|
-
|
69
|
-
$('#filename').keypress (e) ->
|
70
|
-
e = window.event if !e
|
71
|
-
if e.keyCode == 13
|
72
|
-
$('#save-button').click()
|
73
|
-
false
|
74
|
-
else
|
75
|
-
true
|
76
|
-
|
77
|
-
$('#load-button').click (e) ->
|
78
|
-
e.preventDefault()
|
79
|
-
if changed
|
80
|
-
return unless confirm('まだセーブしていないのでロードするとプログラムが消えてしまうよ!それでもロードしますか?')
|
81
|
-
$(@).parent().find('input[name="source_code[file]"]').click()
|
82
|
-
|
83
|
-
$('#file-form').fileupload(
|
84
|
-
dataType: 'json'
|
85
|
-
done: (e, data) ->
|
86
|
-
info = data.result.source_code
|
87
|
-
if info.error
|
88
|
-
msg = $('<div class="alert alert-error" style="display: none">')
|
89
|
-
.append('<button type="button" class="close" data-dismiss="alert">×</button>')
|
90
|
-
.append('<h4><i class="icon-exclamation-sign"></i>エラー</h4>')
|
91
|
-
.append(info.filename + 'は' + info.error)
|
92
|
-
$('#messages').append(msg)
|
93
|
-
msg.fadeIn('slow').delay(5000).fadeOut('slow')
|
94
|
-
else
|
95
|
-
$('#filename').val(info.filename)
|
96
|
-
session.getDocument().setValue(info.data)
|
97
|
-
changed = false
|
98
|
-
)
|
99
|
-
|
100
|
-
window.onbeforeunload = (event) ->
|
101
|
-
if !saving && session.getDocument().getValue().length > 0
|
102
|
-
return '作成中のプログラムが消えてしまいます。'
|
103
|
-
else
|
104
|
-
saving = false
|
105
|
-
return
|