module StatSailr

Constants

VERSION

Public Class Methods

build_exec( script , initR_beforeExec: false , endR_afterExec: false , block_idx_start: 1, set_working_dir: nil, device_info: nil, output_mngr: Output::OutputManager.new(capture: false), procs_gem: "statsailr_procs_base" ) click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 124
def self.build_exec( script , initR_beforeExec: false , endR_afterExec: false , block_idx_start: 1, set_working_dir: nil, device_info: nil,
                     output_mngr: Output::OutputManager.new(capture: false), 
                     procs_gem: "statsailr_procs_base" )

require_relative("scanner/sts_scanner.rb")

output_mngr.move_to_new_node("Tokenize code")
tokens = []
output_mngr.add_new_message(:output).run($stdout){
  s = STSScanDriver.new( script )
  tokens = s.tokenize()
}
output_mngr.move_up()

if tokens.empty?
  puts "Input token is empty"
  if initR_beforeExec
    initR()
    initial_setting_for_r( device_info )

    output_mngr.move_to_new_node("Load PROCs")
    output_mngr.add_new_message(:output).run($stdout){
      initial_procs_registration( procs_gem )
    }
    output_mngr.move_up()
  end
  if endR_afterExec
    endR()
  end
  return 0
end

require_relative("parser/sts_parse.tab.rb")

gram_nodes = nil
output_mngr.move_to_new_node("Parse tokens")
output_mngr.add_new_message(:output).run($stdout){
  gram_nodes = STSParserDriver.run( tokens )
}
output_mngr.move_up()

require_relative("block_builder/sts_block.rb")

blocks = []
gram_nodes.each(){|node|
  case node.type
  when :TOP_BLOCK
    blocks << TopStmt.new_from_gram_node(node)
  when :DATA_BLOCK
    blocks << DataBlock.new_from_gram_node(node)
  when :PROC_BLOCK
    blocks << ProcBlock.new_from_gram_node(node)
  end
}

require_relative("block_to_r/sts_block_to_r.rb")

if initR_beforeExec
  initR()
  initial_setting_for_r( device_info )

  output_mngr.move_to_new_node("Load PROCs")
  output_mngr.add_new_message(:output).run($stdout){
    initial_procs_registration( procs_gem )
  }
  output_mngr.move_up()
end

if ! set_working_dir.nil?
  change_working_dir( set_working_dir )
end

begin
output_mngr.move_to_new_node("BLOCK_TO_R")
block_idx = block_idx_start
blocks.each(){|blk|
  RBridge.ptr_manager_open ("Block No. " + block_idx.to_s) {
    begin
      block_num_str = "BLOCK NO. " + block_idx.to_s + "\n"
      case blk
      when TopStmt
        output_mngr.move_to_new_node("TopStmt")
        output_mngr.add_new_message(:text).set_content( block_num_str )
        output_mngr.add_new_message(:output).run($stdout){
          func = TopStmtToR.create_function( blk )
          RBridge.exec_function_no_return( func ) unless func.nil?
          puts ""
        }
        output_mngr.move_up()
      when DataBlock
        output_mngr.move_to_new_node("DataBlock")
        output_mngr.add_new_message(:text).set_content( block_num_str )
        output_mngr.add_new_message(:output).run($stdout){
          func = DataBlockToR.create_function( blk )
          RBridge.exec_function_no_return( func )
          puts ""
        }
        output_mngr.move_up()
      when ProcBlock
        output_mngr.move_to_new_node(["ProcBlock", blk.command ])
        output_mngr.add_new_message(:text).set_content( block_num_str )
        result_manager = RBridge::RResultManager.new
        lazy_funcs_with_print_result_opts = ProcBlockToR.create_lazy_funcs( blk , @proc_setting_manager )
        lazy_funcs_with_print_result_opts.each(){|lazy_func, print_opt, plot_opt, store_result , result_name |
          output_mngr.move_to_new_node(["inst", result_name])
          output_mngr.add_new_message(:text).set_content( "inst: #{result_name}\n" )
          output_mngr.add_new_message(:output).run($stdout){
            r_obj = RBridge.exec_lazy_function( lazy_func , result_manager , allow_nil_result: true)
            if(store_result)
              result_manager.add_inst_r_obj( result_name, r_obj)
            end
            if(print_opt.nil? || print_opt == false)
              # nop
            elsif(print_opt == true )
              print_func = RBridge::create_function_call("print", { "x" => r_obj } )
              RBridge::exec_function_no_return(print_func)
            elsif(print_opt.is_a? String)
              func_before_print = print_opt
              print_func = RBridge::create_function_call("print", {"x" => RBridge::create_function_call( func_before_print , { "" => r_obj }) })
              RBridge::exec_function_no_return(print_func)
            else
              raise "print_opt needs to be true, false, String."
            end
          }
          output_mngr.add_new_message(:new_line).set_content("\n")

          if( plot_opt.nil? || plot_opt == false || @new_device_info.nil? )
            #nop
          else
            if @new_device_info["file_output"] == true
              # The plot needs to be saved on disk.
              dev_info_opt = @new_device_info["opt"]
              temp_path = ""
              temp_file = Tempfile.new( [dev_info_opt["prefix"] , "." + dev_info_opt["type"] ] , dev_info_opt["dir_path"] )
              temp_path = temp_file.path
              temp_file.close(true)
              dev_copy_func = RBridge::create_function_call("dev.copy", { "device" => dev_info_opt["device_func"], "file" => RBridge::create_strvec([temp_path]),
                                                                          "width" => RBridge::create_intvec( [dev_info_opt["default_width"]] ),
                                                                          "height" => RBridge::create_intvec( [dev_info_opt["default_height"]] ) })
              RBridge::exec_function_no_return(dev_copy_func)
              dev_off_func = RBridge::create_function_call("dev.off", {})
              RBridge::exec_function_no_return(dev_off_func)
              if(File.exist? temp_path)
                output_mngr.add_new_message(:plot_file).set_content( temp_path )
              end
            end
          end
          output_mngr.move_up()
        }
      end
    rescue => e
      e.class.module_eval { attr_accessor :block_num_executed}  # Add block_num_executed attribute to the current error object dynamically.
      e.block_num_executed = block_idx - block_idx_start
      raise e
    end
  }
  puts()
  block_idx = block_idx + 1
}
rescue => error
  puts "stopped working in block no." + block_idx.to_s
  RBridge.gc_all()
  puts "gc is explicitly executed for this block"
  raise
ensure
  output_mngr.move_to_root()
end

if endR_afterExec
  output_mngr.move_to_new_node("INIT_R")
  output_mngr.add_new_message(:output).run($stdout){
    endR()
  }
  output_mngr.move_up()
end

return ( block_idx - block_idx_start ) # number of blocks processed.

end
change_working_dir( set_working_dir ) click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 115
def self.change_working_dir( set_working_dir )
  unless Dir.exists?(set_working_dir)
    raise "New working directory not found: #{set_working_dir}"
  end
  RBridge.exec_function_no_return( RBridge.create_function_call("setwd", {"dir" => RBridge.create_strvec([set_working_dir])}))
  puts "R program working directory is set to #{set_working_dir}"
end
endR() click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 105
def self.endR()
  if ! @new_device_info.nil?
    if @new_device_info["dev_off_required"]
      RBridge.exec_function_no_return( RBridge.create_function_call("dev.off", {}))
    end
  end
  RBridge.end_embedded_r()
  puts "R program safely finished"
end
initR() click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 6
def self.initR()
  RBridge.init_embedded_r()
  puts "R program initialized"
end
initial_procs_registration( procs_gem ) click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 64
def self.initial_procs_registration( procs_gem )
  if @proc_setting_manager.nil?
    @proc_setting_manager = ProcSettingManager.new

    if procs_gem.nil?
      puts "No PROC(s) are instructed to be registered. nil specified."
    elsif ! [String, Array].include? procs_gem.class
      raise "procs_gem needs to be specified in String or Array."
    else
      if procs_gem.class == String
        procs_gem = [procs_gem]
      end

      procs_gems_name_class_array = procs_gem.filter_map(){|gem_name| 
        if gem_name =~ /^statsailr_(\w+)/
          class_name = $1.split("_").map(){|elem| elem.capitalize()}.join("")
          [ gem_name, class_name ]
        else
          raise 'gem name specified for procs_gem is not appropriate. The name pattern should be /^statsailr_(\w+)/'
        end
      }

      puts ("Load gems for PROC settings")
      procs_gems_name_class_array.each{|procs_gem_name, procs_class_name|
      # Add PROCs from gems
        begin
          require(procs_gem_name)
          @proc_setting_manager.add_proc_settings_from_dir( Module.const_get( "StatSailr::" + procs_class_name).send( "path_to_proc_setting") )
          puts "#{procs_gem_name} gem is loaded (ver. #{Gem.loaded_specs[procs_gem_name].version.to_s})"
        rescue LoadError => e
          puts e.message
          puts "#{procs_gem_name} gem failed to be loaded"
          e.set_backtrace( [] )
        rescue NameError
        rescue RuntimeError
        end
      }
    end
  end
end
initial_setting_for_r(device_info) click to toggle source
# File lib/statsailr/sts_build_exec.rb, line 11
def self.initial_setting_for_r(device_info)
  p device_info
  if (! device_info.nil?) && (device_info.is_a? Array )  # (e.g.) ["Gtk3", <FFI::Pointer>]
    device_type = device_info[0]
    case device_type.downcase
    when "gtk3"
      puts "Use asCairoDevice function in cairoDeviceGtk3 library"
      if ! device_info[1].is_a?(FFI::Pointer)
        raise "Pointer to GtkWidget needs to be specified"
      end
      p device_info
      p_widget = device_info[1]
      lib_func = RBridge.create_library_function("cairoDeviceGtk3")
      RBridge.exec_function_no_return(lib_func)
      attach_widget_func = RBridge.create_function_call("asCairoDevice", {"widget" => RBridge.create_extptr(p_widget) } )
      RBridge.exec_function_no_return(attach_widget_func)
      @new_device_info = { "file_output" => false, "dev_off_required" => false }

    when "cairoraster"  # (e.g.) ["CairoRaster", {"width" => 800, "height" => 600, "dev.copy_opt" => {"dir_path"=> dir_to_save , "prefix"=> "plot", "type" => "png"} }]
      puts "Use Cairo function in Cairo library"
      if ! device_info[1].is_a?(Hash)
        raise "The second element of device info needs to be Hash"
      end
      cairo_info = device_info[1]
      if ! ["png", "jpeg"].include? cairo_info["dev.copy_opt"]["type"]
        raise "only png or jpeg is supported for type"
      else
        case cairo_info["dev.copy_opt"]["type"]
        when "png"
          # load png library
          lib_func = RBridge.create_library_function("png")
          RBridge.exec_function_no_return(lib_func)
        when "jpeg"
          # use default jpeg device
        end
      end
      lib_func = RBridge.create_library_function("Cairo")
      RBridge.exec_function_no_return(lib_func)
      new_cairo_device_func = RBridge.create_function_call("Cairo", { "width" => RBridge.create_intvec([ cairo_info["width"] ]),
                                                                      "height" => RBridge.create_intvec([ cairo_info["height"] ]),
                                                                      "type" => RBridge.create_strvec([ "raster" ])  })
      RBridge.exec_function_no_return(new_cairo_device_func)
      @new_device_info = { "file_output" => true, "dev_off_required" => true ,
                           "opt" => cairo_info["dev.copy_opt"].merge( {
                                      "device_func" => RBridge::SymbolR.new( cairo_info["dev.copy_opt"]["type"] ).to_r_symbol,
                                      "default_width" => cairo_info["width"], "default_height" => cairo_info["height"]})}
    else
      puts "Unknown device type: #{device_type}"
    end
  end
  RBridge.exec_function_no_return( RBridge.create_function_call("options", {"warn" => RBridge.create_intvec([ 1 ])} ))
end
run( **kw_args ) click to toggle source
# File lib/statsailr/sts_runner.rb, line 4
def self.run( **kw_args )

  if FileTest.exist?( $script_file_path )
    script_file = File.open( $script_file_path, "r")
    script = script_file.read()
    script_file.close()
  else
    raise( $script_file_path + ":StatSailr source file does not exit")
  end

  StatSailr.build_exec(script, initR_beforeExec: true, endR_afterExec: true, block_idx_start: 1, set_working_dir: File.dirname( $script_file_path ),
                       **kw_args )
end