Странное поведение с переменными экземпляра в Shoes - PullRequest
2 голосов
/ 21 апреля 2011

Привет, все. Я работаю над созданием графического интерфейса для проекта Ruby с использованием Shoes.

У меня есть класс с именем Manager (как в диспетчере памяти), который загружает «список процессов» из файла, разбивает его на части и назначает вещи различным «страницам» в памяти при выполнении определенного вызова выполнения. Я правда не думаю, что эта часть имеет слишком большое значение. Все это работает как терминальное приложение просто отлично.

Однако обувь просто сбивает меня с толку. Вот что у меня так далеко:

Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
  @manager = Manager.new
  stack(:width => 200) do
    @exec_list = stack {
      title "Execution Queue", :size => 14
      @exec_lines = para "click button to load", :size => 9
      @file_button = button "Load Process List"
      @file_button.click {
        filename = ask_open_file
        # @manager.set_exec_list filename
        # alert "this makes no sense"
        @exec_lines.text = @manager.exec_list.join "\n"
        # exec_lines.text = File.read filename
      }
    }
  end
end

Что происходит, когда я запускаю это:

Вид программы загружается как положено. Я получаю заголовок, абзац с надписью "нажмите кнопку ...." и кнопку. Я нажимаю кнопку и выбираю файл. Но здесь все становится странно.

Если я запускаю последнюю закомментированную строку exec_lines.text = File.read filename, она делает так, как мне хотелось бы, но мой менеджер не получает необходимой информации.

Если я запускаю строку @manager.set_exec_list filename, ничего не запускается с этой строки в блоке, включая alert или любой другой код, который я пытаюсь вставить туда.

однако, если я запускаю, как показано выше, я получаю ожидаемый вывод, но не могу установить свои данные из выбранного файла.

Я пытался выяснить это на странице Правила обуви , но, похоже, это не проблема, к которой они обращаются, и их "это меняет / не меняет себя". I Мне кажется, я понимаю, но это сбивает с толку, и я не думаю, что это точно связано с этой проблемой.

У кого-нибудь есть идеи, как заставить это работать? Я немного потрудился над этим проектом, и я не могу заставить работать какой-либо другой инструментарий Ruby GUI, поэтому я думаю, что я довольно застрял в Shoes.

Спасибо.

Обновление Я попытался запустить ruby-debug для кода, когда я выполняю вызов @manager.set_exec_list filename, и пошаговое выполнение показывает, что этот вызов выполнен, но на самом деле код (из того, что я могу сказать) не переходит в этот метод, и действует как последняя строка кода в блоке. Нужно ли включать эти классы в блок Shoes.app? Обновление Нет. Это ничем не отличается.

обновление следующий исходный код:

#!/usr/bin/env shoes
require 'rubygems'
require 'ruby-debug'

class MemSegment
  attr_accessor :filled, :pid, :seg, :seg_id

  def initialize(filled=false, pid=nil, seg=nil, seg_id=0)
    @filled = filled
    @pid = pid.to_i
    @seg = seg.to_s
    @seg_id = seg_id.to_i
    self
  end

  def fill(pid, seg, seg_id)
    @filled = true; @pid = pid; @seg = seg; @seg_id = seg_id;
    self
  end

  def clear
    self.filled = false; self.pid = nil; self.seg = nil;
    self
  end

  def filled?
    @filled
  end

  def to_s
    filled? ? "#{seg} #{seg_id} for pid #{pid}" : "Free"
  end
end

class SimProc
  include Enumerable
  attr_accessor :pid, :code, :data

  def initialize(pid, code, data)
    @pid = pid.to_i
    @code = code.to_i
    @data = data.to_i
  end

  def each
    yield :code, code
    yield :data, data
  end

  def to_s
    "[SimProc :pid => #{pid}, :code => #{code}, :data => #{data}]"
  end

  def to_a
    [@pid, @code, @data]
  end
end

class Manager
  attr_reader :segments, :processes, :exec_list, :exec_object

  def initialize
    @exec_list = [[1, 2], [3, 4], [5, 6]]
    @processes = {}
    @segments = Array.new(8) { MemSegment.new }
  end

  def print_activity
    @segments.each_with_index {|s, index| puts "Seg #{index} => #{s}" }
    @processes.each_value {|s| puts s }
  end

  def load_process(pcb, exec_index)
    if pcb.size == 3
      p = SimProc.new(*pcb)
      bad_load = false

      @processes.store p.pid, p
      @processes[p.pid].each do |proc_seg, bsize|
        (bsize / 512.0).ceil.times do |seg_id|
          @segments.each_with_index do |s, index|
            if !s.filled
              #find the first empty memory segment
              s.fill p.pid, proc_seg, seg_id
              break
            # if all slots are filled and we couldn't place a proc block
            elsif index == @segments.size - 1
              bad_load = true
              puts "Cannot find a place for #{proc_seg} segment of size #{bsize}. Requeueing..."
              break;
            end
          end
          break if bad_load
        end
      end
      # recover pages and queue the process for later
      if bad_load
        @segments.each_with_index do |seg, seg_index|
          # clear any segments that didn't get loaded properly
          if seg.pid == p.pid
            seg.clear
            puts "Seg #{seg_index} => segment cleared: #{seg}"
          end
        end
        # reinsert this process after the next in the execution list
        # it will attempt to load and run after the next process is performed
        @exec_list.insert(exec_index + 2, p.to_a)
      end
      print_activity

    elsif pcb.size == 2 and pcb[1] == -1
      # a process is exiting
      puts "removing pid #{pcb[0]}"
      @segments.each { |s| s.clear if s.pid == pcb[0] }
      @processes.delete pcb[0]
      print_activity
    end
  end

  def set_exec_list(filename)
    file = File.open filename
    file.each { |pcb| @exec_list << pcb.split.map(&:to_i) } unless file.nil?
    filename
  end

  def main
    exseq = File.open('exseq2.txt')
    set_exec_list exseq

    # this is the object that will be used to run each process with .next
    @exec_object = @exec_list.each_with_index
    # @exec_list.each_with_index { |pcb, exec_index| load_process(pcb, exec_index) }
    (@exec_list.size + 1).times do
      load_process(*@exec_object.next)
    end
  end
end

=begin
manager = Manager.new
manager.main
=end

#=begin
Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
  @manager = Manager.new
  stack(:width => 200) do
    @exec_list = stack {
      title "Execution Queue", :size => 14
      @exec_lines = para "click button to load", :size => 9
      @file_button = button "Load Process List"
      debugger
      @file_button.click {
        filename = ask_open_file
        @manager.set_exec_list filename
        # alert "this makes no sense"
        # @exec_lines.text = @manager.exec_list
        # @exec_lines.text = File.read filename
        @exec_lines.text = @manager.exec_list.join "\n"
      }
    }
  end
end
#=end

1 Ответ

3 голосов
/ 21 апреля 2011

Итак, несколько вещей:

# 1, у меня нет реализации Manager, поэтому я не могу сказать вам, почему она ломается. Вы пытались проверить консоль Shoes на наличие ошибок? Нажмите Control- /, чтобы поднять это. Если «ничего не происходит после того, как оно попадает в эту строку», это, вероятно, проблема.

# 2, это работает для меня, если вы измените exec_lines на @exec_lines в последней строке. Вот что я попробовал:

class Manager;end
Shoes.app(:title => "Paging Simulator", :width => 800, :height => 450) do
  @manager = Manager.new
  stack(:width => 200) do
    @exec_list = stack {
      title "Execution Queue", :size => 14
      @exec_lines = para "click button to load", :size => 9
      @file_button = button "Load Process List"
      @file_button.click {
        filename = ask_open_file
        #alert "this makes no sense"
        @exec_lines.text = File.read filename
      }
    }
  end
end

Надеюсь, это поможет!

...