smalruby-editor 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
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
|