Shoes 中实例变量的奇怪行为

发布于 2024-11-02 07:37:36 字数 5848 浏览 4 评论 0原文

嘿,全部。我正在使用 Shoes 为 Ruby 项目制作 GUI。

我有一个名为 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 或任何其他我尝试将代码放在那里。

但是,如果我如上所示运行,我会得到预期的输出,但无法从我选择的文件中设置数据。

我试图从 鞋子规则 页面弄清楚这一点,但这似乎并不是他们解决的一个问题,他们的“它改变/不改变自我”我想我明白了,但这很令人困惑,我不认为它与这个问题完全相关。

有谁知道如何让它发挥作用吗?我在这个项目上处于紧要关头,而且我似乎无法运行任何其他 Ruby GUI 工具包,所以我认为我对 Shoes 非常着迷。

谢谢。

更新 当我调用 @manager.set_exec_list filename 时,我尝试在代码上运行 ruby​​-debug,单步执行它表明已进行此调用,但代码实际上从未(根据我的内容)可以告诉)跳转到该方法,并且就像块中的最后一行代码一样。我是否需要将这些类包含在 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

Hey, all. I'm working on making a GUI for a Ruby project using Shoes.

I've got a class called Manager (as in memory manager) that loads a 'process list' from a file, splits it up and assigns things to different 'pages' in memory when a certain execution call is made. I really don't think this part matters too much, though. It all works as a terminal application just fine.

However, Shoes is just baffling me. Here's what I've got so far:

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

What happens when I run this:

The program view loads as expected. I get a header, a paragraph that says "click button....", and a button. I click the button and I select the file. But this is where things get weird.

If I run the last commented line exec_lines.text = File.read filename it does as I would like, but my manager doesn't get any of the information it needs.

If I run the @manager.set_exec_list filename line, nothing from that line on in the block gets run, including the alert, or any other code I try to put in there.

if I run as shown above, however, I get the output I expect, but I don't get to set my data from the file that I select.

I've tried to figure this out from the Shoes Rules page, but this doesn't seem to be an issue that they address, and their "it changes/doesn't change self" I think I grasp, but it's confusing and I don't think it's exactly related to this problem.

Does anyone have any idea how to get this to work? I'm kind of down to crunch time on this project and I can't seem to get any other Ruby GUI toolkit to even run, so I think I'm pretty stuck with Shoes.

Thanks.

Update
I've tried running ruby-debug on the code when I make the call to @manager.set_exec_list filename, and stepping through it shows that this call is made, but the code never actually (from what I can tell) jumps into that method, and acts like it's the last line of code in the block. Do I need to include these classes inside the Shoes.app block?
Update Nope. That does nothing different.

update fullsource code follows:

#!/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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

三生殊途 2024-11-09 07:37:36

所以,有几件事:

#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

希望有帮助!

So, a few things:

#1, I don't have the implementation of Manager, so I can't tell you why it breaks. Did you try checking the Shoes console for any errors? Hit control-/ to bring that up. If 'nothing runs after it hits that line,' that's probably the issue.

#2, this does work for me, as long as you change exec_lines to @exec_lines on the last line. Here's what I tried:

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

Hope that helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文