smalruby-editor 0.0.5 → 0.0.6

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.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -1
  4. data/.rubocop.yml +18 -0
  5. data/.travis.yml +24 -23
  6. data/LEGAL +13 -0
  7. data/README.rdoc +1 -0
  8. data/Rakefile +3 -0
  9. data/app/assets/javascripts/application.js +1 -1
  10. data/app/assets/javascripts/editor.js.coffee +60 -15
  11. data/app/assets/stylesheets/application.css +1 -2
  12. data/app/assets/stylesheets/flatstrap-custom.css.scss +2 -0
  13. data/app/controllers/editor_controller.rb +0 -24
  14. data/app/controllers/source_codes_controller.rb +67 -0
  15. data/app/models/source_code.rb +42 -0
  16. data/app/views/editor/index.html.erb +5 -3
  17. data/bin/smalruby-editor +11 -0
  18. data/config/application.rb +8 -20
  19. data/config/boot.rb +3 -0
  20. data/config/environments/development.rb +2 -1
  21. data/config/environments/production.rb +12 -6
  22. data/config/environments/standalone.rb +3 -2
  23. data/config/environments/test.rb +14 -4
  24. data/config/initializers/backtrace_silencers.rb +4 -2
  25. data/config/initializers/session_store.rb +2 -1
  26. data/config/initializers/wrap_parameters.rb +2 -1
  27. data/config/routes.rb +10 -6
  28. data/config/unicorn.rb +7 -6
  29. data/db/migrate/20131216121603_create_source_codes.rb +9 -0
  30. data/db/migrate/20131219045113_add_filename_to_source_code.rb +5 -0
  31. data/db/schema.rb +8 -1
  32. data/lib/smalruby_editor.rb +29 -15
  33. data/lib/smalruby_editor/version.rb +1 -1
  34. data/lib/tasks/rspec.rake +2 -2
  35. data/lib/tasks/rubocop.rake +3 -0
  36. data/public/fonts/FontAwesome.otf +0 -0
  37. data/public/fonts/fontawesome-webfont.eot +0 -0
  38. data/public/fonts/fontawesome-webfont.ttf +0 -0
  39. data/public/fonts/fontawesome-webfont.woff +0 -0
  40. data/smalruby-editor.gemspec +3 -3
  41. data/spec/acceptance/readme.md +3 -0
  42. data/spec/acceptance/text_editor/base.feature +24 -0
  43. data/spec/acceptance/text_editor/check.feature +20 -0
  44. data/spec/acceptance/text_editor/load.feature +74 -0
  45. data/spec/acceptance/text_editor/save.feature +31 -0
  46. data/spec/controllers/editor_controller_spec.rb +2 -63
  47. data/spec/controllers/source_codes_controller_spec.rb +296 -0
  48. data/spec/models/source_code_spec.rb +44 -0
  49. data/spec/spec_helper.rb +123 -65
  50. data/spec/steps/ace_steps.rb +60 -0
  51. data/spec/steps/global_variable.rb +39 -0
  52. data/spec/steps/text_editor_steps.rb +160 -0
  53. data/spec/support/capybara.rb +17 -0
  54. metadata +49 -19
  55. data/spec/acceptance/editor.feature +0 -68
  56. data/spec/steps/editor_steps.rb +0 -123
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe SourceCode, 'Rubyのソースコードを表現するモデル' do
5
+ describe '#check_syntax', 'シンタックスをチェックする' do
6
+ let(:source_code) {
7
+ SourceCode.new(data: data)
8
+ }
9
+
10
+ subject { source_code.check_syntax }
11
+
12
+ context 'シンタックスが正しい場合' do
13
+ let(:data) { 'puts "Hello, World!"' }
14
+
15
+ it { should be_empty }
16
+ end
17
+
18
+ context 'シンタックスが正しくない場合' do
19
+ let(:data) { 'puts Hello, World!"' }
20
+
21
+ it { should_not be_empty }
22
+ it {
23
+ should include(row: 1, column: 19,
24
+ message: 'syntax error, unexpected tSTRING_BEG,' \
25
+ " expecting keyword_do or '{' or '('")
26
+ }
27
+ it {
28
+ should include(row: 1, column: 0,
29
+ message: 'unterminated string meets end of file')
30
+ }
31
+ end
32
+ end
33
+
34
+ describe '#digest', 'プログラムのハッシュ値を計算する' do
35
+ let(:data) { 'puts "Hello, World!"' }
36
+ let(:source_code) {
37
+ SourceCode.new(data: data)
38
+ }
39
+
40
+ subject { source_code.digest }
41
+
42
+ it { should eq(Digest::SHA256.hexdigest(data)) }
43
+ end
44
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,70 +1,128 @@
1
- # This file is copied to spec/ when you run 'rails generate rspec:install'
2
- ENV["RAILS_ENV"] ||= 'test'
3
- require File.expand_path("../../config/environment", __FILE__)
4
- require 'rspec/rails'
5
- require 'rspec/autorun'
6
- require 'capybara/dsl'
7
- require 'capybara/rspec'
8
- require 'capybara/poltergeist'
9
- require 'turnip'
10
- require 'turnip/capybara'
11
- require 'simplecov' if ENV['COVERAGE'] || ENV['COVERALLS']
12
-
13
- # Requires supporting ruby files with custom matchers and macros, etc,
14
- # in spec/support/ and its subdirectories.
15
- Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
16
-
17
- Dir.glob("spec/steps/**/*_steps.rb") { |f| load f, true }
18
-
19
- # Checks for pending migrations before tests are run.
20
- # If you are not using ActiveRecord, you can remove this line.
21
- ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
22
-
23
- RSpec.configure do |config|
24
- # ## Mock Framework
25
- #
26
- # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
27
- #
28
- # config.mock_with :mocha
29
- # config.mock_with :flexmock
30
- # config.mock_with :rr
31
-
32
- # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
33
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
34
-
35
- # If you're not using ActiveRecord, or you'd prefer not to run each of your
36
- # examples within a transaction, remove the following line or assign false
37
- # instead of true.
38
- config.use_transactional_fixtures = true
39
-
40
- # If true, the base class of anonymous controllers will be inferred
41
- # automatically. This will be the default behavior in future versions of
42
- # rspec-rails.
43
- config.infer_base_class_for_anonymous_controllers = false
44
-
45
- # Run specs in random order to surface order dependencies. If you find an
46
- # order dependency and want to debug it, you can fix the order by providing
47
- # the seed, which is printed after each run.
48
- # --seed 1234
49
- config.order = "random"
50
-
51
-
52
- case (ENV['TARGET_WEB_BROWZER'] || ENV['TWB']).try(:downcase)
53
- when 'firefox'
54
- Capybara.javascript_driver = :selenium
55
- when 'ie'
56
- Capybara.register_driver :selenium_ie do |app|
57
- Capybara::Selenium::Driver.new(app, browser: :ie, introduce_flakiness_by_ignoring_security_domains: true)
1
+ # -*- coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'spork'
4
+ # uncomment the following line to use spork with the debugger
5
+ # require 'spork/ext/ruby-debug'
6
+
7
+ Spork.prefork do
8
+ # Loading more in this block will cause your tests to run faster. However,
9
+ # if you change any configuration or code from libraries loaded here, you'll
10
+ # need to restart spork for it take effect.
11
+
12
+ ENV['RAILS_ENV'] ||= 'test'
13
+ require File.expand_path('../../config/environment', __FILE__)
14
+ require 'rspec/rails'
15
+ require 'rspec/autorun'
16
+ require 'capybara/dsl'
17
+ require 'capybara/rspec'
18
+ require 'capybara/poltergeist'
19
+ require 'turnip'
20
+ require 'turnip/capybara'
21
+ require 'simplecov' if ENV['COVERAGE'] || ENV['COVERALLS']
22
+
23
+ # Requires supporting ruby files with custom matchers and macros, etc,
24
+ # in spec/support/ and its subdirectories.
25
+ Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
26
+
27
+ load 'spec/steps/global_variable.rb', true
28
+ Dir.glob('spec/steps/**/*_steps.rb') { |f| load f, true }
29
+
30
+ # Checks for pending migrations before tests are run.
31
+ # If you are not using ActiveRecord, you can remove this line.
32
+ ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
33
+
34
+ RSpec.configure do |config|
35
+ # ## Mock Framework
36
+ #
37
+ # If you prefer to use mocha, flexmock or RR, uncomment the
38
+ # appropriate line:
39
+ #
40
+ # config.mock_with :mocha
41
+ # config.mock_with :flexmock
42
+ # config.mock_with :rr
43
+
44
+ # Remove this line if you're not using ActiveRecord or
45
+ # ActiveRecord fixtures
46
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
47
+
48
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
49
+ # examples within a transaction, remove the following line or assign false
50
+ # instead of true.
51
+ config.use_transactional_fixtures = true
52
+
53
+ # If true, the base class of anonymous controllers will be inferred
54
+ # automatically. This will be the default behavior in future versions of
55
+ # rspec-rails.
56
+ config.infer_base_class_for_anonymous_controllers = false
57
+
58
+ # Run specs in random order to surface order dependencies. If you find an
59
+ # order dependency and want to debug it, you can fix the order by providing
60
+ # the seed, which is printed after each run.
61
+ # --seed 1234
62
+ config.order = 'random'
63
+
64
+ twb = (ENV['TARGET_WEB_BROWZER'] || ENV['TWB']).try(:downcase)
65
+ case twb
66
+ when 'firefox', 'ie', 'chrome'
67
+ Capybara.register_driver :selenium do |app|
68
+ opts = { browser: twb.to_sym }
69
+
70
+ dir = downloads_dir.to_s
71
+ dir.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if windows?
72
+ case twb
73
+ when 'firefox'
74
+ opts[:profile] = profile = Selenium::WebDriver::Firefox::Profile.new
75
+ profile['browser.download.folderList'] = 2 # custom location
76
+ profile['browser.download.dir'] = dir
77
+ profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/plain'
78
+ when 'ie'
79
+ opts[:introduce_flakiness_by_ignoring_security_domains] = true
80
+ when 'chrome'
81
+ FileUtils.mkdir_p(dir)
82
+ opts[:prefs] = {
83
+ download: {
84
+ prompt_for_download: false,
85
+ default_directory: dir,
86
+ directory_upgrade: true,
87
+ }
88
+ }
89
+
90
+ opts[:switches] =
91
+ %w(
92
+ --ignore-certificate-errors
93
+ --disable-popup-blocking
94
+ --disable-translate
95
+ )
96
+ end
97
+
98
+ Capybara::Selenium::Driver.new(app, opts)
99
+ end
100
+ Capybara.javascript_driver = :selenium
101
+ else
102
+ Capybara.javascript_driver = :poltergeist
58
103
  end
59
- Capybara.javascript_driver = :selenium_ie
60
- when 'chrome'
61
- Capybara.register_driver :selenium_chrome do |app|
62
- Capybara::Selenium::Driver.new(app, browser: :chrome)
104
+
105
+ config.include JsonSpec::Helpers
106
+
107
+ config.after(javascript: true) do
108
+ page.execute_script('window.onbeforeunload = null')
109
+ if selenium?
110
+ FileUtils.rm_rf(downloads_dir)
111
+ end
63
112
  end
64
- Capybara.javascript_driver = :selenium_chrome
65
- else
66
- Capybara.javascript_driver = :poltergeist
67
113
  end
114
+ end
115
+
116
+ Spork.each_run do
117
+ # This code will be run each time you run your specs.
68
118
 
69
- config.include JsonSpec::Helpers
119
+ # http://penguinlab.jp/blog/post/2256# より
120
+ if Spork.using_spork?
121
+ # app 下のファイル / locale / routes をリロード
122
+ # railties-3.2.3/lib/rails/application/finisher.rb あたりを参考に
123
+ Rails.application.reloaders.each { |reloader| reloader.execute_if_updated }
124
+
125
+ # machinist gem を利用してる場合、blueprints を再度読み直す
126
+ # load "#{File.dirname(__FILE__)}/support/blueprints.rb"
127
+ end
70
128
  end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ text_editor = 'テキストエディタ'
4
+
5
+ step 'テキストエディタにフォーカスがあること' do
6
+ expect(page.evaluate_script(<<-JS)).to be_true
7
+ $('#{NAME_INFO[text_editor][:selector]} textarea.ace_text-input').get(0) ==
8
+ document.activeElement
9
+ JS
10
+ end
11
+
12
+ step 'テキストエディタの :row 行目の :column 文字目にカーソルがあること' do |row, column|
13
+ get_cursor_position_js =
14
+ "ace.edit('#{NAME_INFO[text_editor][:id]}').getCursorPosition()"
15
+ expect(page.evaluate_script("#{get_cursor_position_js}.row")).to eq(row.to_i)
16
+ expect(page.evaluate_script("#{get_cursor_position_js}.column"))
17
+ .to eq(column.to_i)
18
+ end
19
+
20
+ step 'テキストエディタに :program を入力済みである' do |program|
21
+ send 'テキストエディタにプログラムを入力済みである:', program
22
+ end
23
+
24
+ step 'テキストエディタにプログラムを入力済みである:' do |program|
25
+ page.execute_script(<<-JS)
26
+ ace.edit('#{NAME_INFO[text_editor][:id]}')
27
+ .getSession()
28
+ .getDocument()
29
+ .setValue('#{program.gsub(/'/, "\\\\'")}')
30
+ JS
31
+ end
32
+
33
+ step 'テキストエディタに :filename を読み込むこと' do |filename|
34
+ js = <<-JS
35
+ ace.edit('#{NAME_INFO[text_editor][:id]}')
36
+ .getSession()
37
+ .getDocument()
38
+ .getValue()
39
+ JS
40
+ path = Pathname(fixture_path).join(filename)
41
+ expect(page.evaluate_script(js)).to eq(path.read)
42
+ end
43
+
44
+ step 'テキストエディタのプログラムは以下であること:' do |program|
45
+ expect(page.evaluate_script(<<-JS)).to eq(program)
46
+ ace.edit('#{NAME_INFO[text_editor][:id]}')
47
+ .getSession()
48
+ .getDocument()
49
+ .getValue()
50
+ JS
51
+ end
52
+
53
+ step 'テキストエディタのプログラムは :program であること' do |program|
54
+ expect(page.evaluate_script(<<-JS)).to eq(program)
55
+ ace.edit('#{NAME_INFO[text_editor][:id]}')
56
+ .getSession()
57
+ .getDocument()
58
+ .getValue()
59
+ JS
60
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ::NAME_INFO = {
4
+ 'トップページ' => {
5
+ path: '/',
6
+ },
7
+ 'エディタ' => {
8
+ path: '/',
9
+ },
10
+
11
+ 'Rubyタブ' => {
12
+ id: 'ruby-tab',
13
+ selector: '#ruby-tab',
14
+ },
15
+ 'テキストエディタ' => {
16
+ id: 'text-editor',
17
+ selector: '#text-editor',
18
+ },
19
+ 'プログラム名の入力欄' => {
20
+ id: 'filename',
21
+ selector: '#filename',
22
+ },
23
+ 'チェックボタン' => {
24
+ id: 'check-button',
25
+ selector: '#check-button',
26
+ },
27
+ 'セーブボタン' => {
28
+ id: 'save-button',
29
+ selector: '#save-button',
30
+ },
31
+ 'ロードボタン' => {
32
+ id: 'load-button',
33
+ selector: '#load-button',
34
+ },
35
+ 'メッセージ' => {
36
+ id: 'messages',
37
+ selector: '#messages',
38
+ },
39
+ }
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+
3
+ step ':name にアクセスする' do |name|
4
+ visit NAME_INFO[name][:path]
5
+
6
+ if poltergeist?
7
+ page.execute_script(<<-JS)
8
+ if (window.confirmMsg == undefined) {
9
+ window.confirmMsg = null;
10
+ window.confirm = function(msg) {
11
+ window.confirmMsg = msg;
12
+ return true;
13
+ }
14
+ }
15
+ JS
16
+ end
17
+ end
18
+
19
+ step ':name が表示されていること' do |name|
20
+ expect(page).to have_selector(NAME_INFO[name][:selector])
21
+ end
22
+
23
+ step ':name 画面を表示する' do |name|
24
+ send ':name にアクセスする', name
25
+ end
26
+
27
+ step 'プログラムの名前に :filename を指定する' do |filename|
28
+ fill_in('filename', with: filename)
29
+ end
30
+
31
+ step ':name をクリックする' do |name|
32
+ click_on(NAME_INFO[name][:id])
33
+ end
34
+
35
+ step 'ダウンロードが完了するまで待つ' do
36
+ start_time = Time.now
37
+ if poltergeist?
38
+ until page.response_headers['Content-Disposition'] ||
39
+ (start_time + 5.seconds) < Time.now
40
+ sleep 1
41
+ end
42
+ elsif selenium?
43
+ until downloads_dir.exist? || (start_time + 5.seconds) < Time.now
44
+ sleep 1
45
+ end
46
+ end
47
+ end
48
+
49
+ step ':filename をダウンロードすること' do |filename|
50
+ step 'ダウンロードが完了するまで待つ'
51
+ if poltergeist?
52
+ expect(page.response_headers['Content-Disposition'])
53
+ .to eq("attachment; filename=\"#{filename}\"")
54
+ expect(page.response_headers['Content-Type'])
55
+ .to eq('text/plain; charset=utf-8')
56
+ elsif selenium?
57
+ expect(downloads_dir.join(filename)).to be_exist
58
+ end
59
+ end
60
+
61
+ step 'ダウンロードしないこと' do
62
+ if poltergeist?
63
+ expect(page.response_headers['Content-Disposition']).to be_nil
64
+ elsif selenium?
65
+ expect(downloads_dir).not_to be_exist
66
+ end
67
+ end
68
+
69
+ step ':name にフォーカスがあること' do |name|
70
+ # HACK: 現在のPhantomJSでは$(':focus')は動作しない
71
+ # https://github.com/netzpirat/guard-jasmine/issues/48
72
+ expect(page.evaluate_script(<<-JS)).to be_true
73
+ $('#{NAME_INFO[name][:selector]}').get(0) == document.activeElement
74
+ JS
75
+ end
76
+
77
+ step ':filename をロードする' do |filename|
78
+ # HACK: input#load-file[type="file"]は非表示要素であるため、.show()し
79
+ # ないと見つけられずattach_fileが失敗する
80
+ page.execute_script("$('#load-file').show()")
81
+
82
+ path = Pathname(fixture_path).join(filename).to_s
83
+ path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if windows?
84
+ attach_file('load-file', path)
85
+ end
86
+
87
+ step 'JavaScriptによるリクエストが終わるまで待つ' do
88
+ start_time = Time.now
89
+ until page.evaluate_script('jQuery.isReady && jQuery.active == 0') ||
90
+ (start_time + 5.seconds) < Time.now
91
+ sleep 1
92
+ end
93
+ end
94
+ step ':name は :value であること' do |name, value|
95
+ expect(page.evaluate_script(<<-JS)).to eq(value)
96
+ $('#{NAME_INFO[name][:selector]}').val()
97
+ JS
98
+ end
99
+
100
+ step ':name に :message を含むこと' do |name, message|
101
+ expect(page.find(NAME_INFO[name][:selector])).to have_content(message)
102
+ end
103
+
104
+ step ':name に :message を含まないこと' do |name, message|
105
+ expect(page.find(NAME_INFO[name][:selector])).to have_no_content(message)
106
+ end
107
+
108
+ step 'ページをリロードする' do
109
+ begin
110
+ step '"エディタ" 画面を表示する'
111
+ rescue Capybara::Poltergeist::TimeoutError => e
112
+ Rails.logger.debug("#{e.class.name}: #{e.message}")
113
+ end
114
+ end
115
+
116
+ step '警告ダイアログの :name ボタンをクリックする' do |name|
117
+ case name
118
+ when 'dismiss'
119
+ page.driver.browser.switch_to.alert.dismiss if selenium?
120
+ else
121
+ page.driver.browser.switch_to.alert.accept if selenium?
122
+ end
123
+ end
124
+
125
+ step '確認メッセージ :message を表示すること' do |message|
126
+ if poltergeist?
127
+ actual = page.evaluate_script('window.confirmMsg')
128
+ page.execute_script('window.confirmMsg = null')
129
+ expect(actual).to eq(message)
130
+ elsif selenium?
131
+ expect(page.driver.browser.switch_to.alert.text).to eq(message)
132
+ page.driver.browser.switch_to.alert.dismiss
133
+ end
134
+ end
135
+
136
+ step '確認メッセージを表示しないこと' do
137
+ if poltergeist?
138
+ actual = page.evaluate_script('window.confirmMsg')
139
+ page.execute_script('window.confirmMsg = null')
140
+ expect(actual).to be_nil
141
+ elsif selenium?
142
+ expect {
143
+ page.driver.browser.switch_to.alert
144
+ }.to raise_exception(Selenium::WebDriver::Error::NoAlertPresentError)
145
+ end
146
+ end
147
+
148
+ step '実際にはファイルをロードしないようにしておく' do
149
+ if selenium?
150
+ page.execute_script("$('#load-button').off('click')")
151
+ page.execute_script(<<-JS)
152
+ $('#load-button').click(function(e) {
153
+ e.preventDefault();
154
+ if (changed) {
155
+ confirm('まだセーブしていないのでロードするとプログラムが消えてしまうよ!それでもロードしますか?');
156
+ }
157
+ })
158
+ JS
159
+ end
160
+ end