app/controllers/source_codes_controller.rb
# -*- coding: utf-8 -*-
require 'nkf'
class SourceCodesController < ApplicationController
before_filter :check_whether_standalone, only: [:write, :run, :load_local]
def index
res = {
localPrograms: [],
demoPrograms: [],
}
select_and_get_summary = proc { |path|
s = SourceCode.new(filename: path.basename.to_s, data: path.read)
next if raspberrypi? && s.include_block?(/^(hardware_|pen_)/)
s.summary
}
if standalone?
res[:localPrograms] =
local_program_paths.map(&select_and_get_summary).compact
end
res[:demoPrograms] =
demo_program_paths.map(&select_and_get_summary).compact
render json: res
end
def check
render json: SourceCode.new(source_code_params).check_syntax
end
def create
sc = SourceCode.create!(source_code_params)
session[:source_code] = {
id: sc.id,
digest: sc.digest,
}
render json: { source_code: { id: sc.id } }
end
def download
send_data(source_code.data,
filename: url_encode_filename(source_code.filename),
disposition: 'attachment',
type: 'text/plain; charset=utf-8')
destroy_source_code_and_delete_session(source_code)
end
def write
res = { source_code: { filename: source_code.filename } }
write_source_code(source_code)
destroy_source_code_and_delete_session(source_code)
render json: res
rescue => e
res[:source_code][:error] = e.message
render json: res
end
def load
f = params[:source_code][:file]
info = get_file_info(f)
if /\Atext\/plain/ =~ info[:type]
info[:data] = NKF.nkf('-w', f.read)
else
info[:error] = I18n.t('.not_ruby_program',
scope: 'controllers.source_codes')
end
render json: { source_code: info }, content_type: request.format
end
def load_local
filename = source_code_params[:filename]
program_path = local_program_paths.find { |path|
rb_basename(path) == filename
}
load_local_file(program_path, source_code_params[:remix])
end
def load_demo
filename = source_code_params[:filename]
program_path = demo_program_paths.find { |path|
rb_basename(path) == filename
}
load_local_file(program_path, source_code_params[:remix])
end
def run
source_code = SourceCode.new(source_code_params)
if session[:username]
s = "~/#{session[:username]}/#{source_code.filename}"
else
s = "~/#{source_code.filename}"
end
path = Pathname(s).expand_path
env = {}
if current_preferences["hardware_port"].present?
env["SMALRUBOT_DEVICE"] = current_preferences["hardware_port"]
end
render json: source_code.run(path, env)
end
def to_blocks
source_code = SourceCode.new(source_code_params)
render text: source_code.to_blocks
rescue
if Rails.env == 'development'
raise
else
head :bad_request
end
end
private
def source_code_params
params.require(:source_code).permit(:data, :filename, :remix)
end
def get_file_info(file)
{
filename: file.original_filename,
type: MIME.check(file.path).try(:content_type) || file.content_type,
size: file.size,
}
end
def url_encode_filename(filename)
if request.env['HTTP_USER_AGENT'] =~ /MSIE|Trident/
return ERB::Util.url_encode(filename)
else
filename
end
end
def source_code
return @source_code if @source_code
sc = SourceCode.find(session[:source_code][:id])
unless sc.digest == session[:source_code][:digest]
fail ActiveRecord::RecordNotFound
end
@source_code = sc
end
def write_source_code(source_code)
if session[:username]
s = "~/#{session[:username]}/#{source_code.filename}"
else
s = "~/#{source_code.filename}"
end
path = Pathname(s).expand_path.to_s
if File.exist?(path) && params[:force].blank?
fail I18n.t('.exist', scope: 'controllers.source_codes')
end
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') do |f|
f.write(source_code.data)
end
end
def destroy_source_code_and_delete_session(source_code)
source_code.destroy
session[:source_code] = nil
end
def local_program_paths
if session[:username]
# TODO: session[:username]の/や\をエスケープする
s = "~/#{session[:username]}/*.rb.xml"
else
s = '~/*.rb.xml'
end
Pathname.glob(Pathname(s).expand_path)
end
def demo_program_paths
Pathname.glob(Rails.root.join('demos/*.rb.xml')) +
Pathname.glob(SmalrubyEditor.home_directory.join('demos/*.rb.xml'))
end
def rb_basename(path)
path = path.basename.to_s
path = path[0...-4] if /\.xml\z/ =~ path
path
end
def load_local_file(path, remix)
if path
if remix == 'true'
filename = SourceCode.make_remix_filename("~/#{session[:username]}",
path.basename.to_s)
else
filename = path.basename.to_s
end
info = {
filename: filename,
type: MIME.check(path.to_s).try(:content_type) || 'text/plain',
data: NKF.nkf('-w', path.read),
size: path.size,
}
else
info = {
filename: source_code_params[:filename],
error: I18n.t('.not_exist', scope: 'controllers.source_codes'),
}
end
render json: { source_code: info }, content_type: request.format
end
end