【问题标题】:Send messages to a global buffer in Ruby将消息发送到 Ruby 中的全局缓冲区
【发布时间】:2014-04-30 11:16:12
【问题描述】:

我知道 Ruby 不鼓励使用全局变量,但这是我被要求做的,所以你只需要和我一起做。我有一个游戏可以通过 STDOUT 成功地将消息输出到命令窗口。我的任务是修改类,使消息不仅显示到 STDOUT 通道,而且写入缓冲区。因此,当我在文件末尾添加一个额外的 Sinatra 方法时,缓冲区会显示在浏览器中(即 localhost:4567)。

如此有效,调用 Sinatra gem 后,从命令窗口运行 spec.rb 应该会导致消息显示在 Web 服务器中以及命令窗口中。但是我不知道从哪里开始将我的消息输出到缓冲区。

我很确定对此有一个非常简单的答案,但我对 ruby​​ 的了解并不多。我的想法是我需要在每个活动中添加一行,将每个活动的输出连接到全局变量 $buffer 但我该怎么做呢?显然,在此之后,我需要编写一个 Sinatra 方法,在 Web 浏览器中显示全局变量的内容。

希望这是有道理的。

我有两个文件,spec.rb 和 gen.rb。到目前为止,这是我的代码:

spec.rb

require "gen.rb"

module ImpossibleMachine
    # Input and output constants processed by subprocesses
    DOWN_ARROW = 1
    UP_ARROW = 2
    RIGHT_ARROW = 3
    REPEAT_ARROW = 4
    END_PROCESS = 5 
    START_CURRENT = 6

    # RSpec Tests 
    describe Game do
        describe "#start The impossible machine game" do
            before(:each) do
                @process = []
                @output = double('output').as_null_object
                @game = Game.new(@output)
            end
            it "sends a welcome message" do
                @output.should_receive(:puts).with('Welcome to the Impossible Machine!')
                @game.start
            end
            it "sends a starting message" do
                @output.should_receive(:puts).with('Starting game...')
                @game.start         
            end
            it "should perform lifts_lever_turns_wheel activity which returns REPEAT_ARROW" do
                @output.should_receive(:puts).with("Input: #{UP_ARROW}, Activity: Heave_ho_squeek_squeek")
                @process[1] = @game.lifts_lever_turns_wheel(UP_ARROW)
                @process[1].should == REPEAT_ARROW
            end
            it "should perform turns_tap_on_pulls_down_seesaw activity which returns DOWN_ARROW" do
                @output.should_receive(:puts).with("Input: #{REPEAT_ARROW}, Activity: Drip_drip_creek_creek")
                @process[2] = @game.turns_tap_on_pulls_down_seesaw(REPEAT_ARROW)
                @process[2].should == DOWN_ARROW
            end
            it "should perform pulls_down_seezaw_starts_current activity which returns START_CURRENT" do
                @output.should_receive(:puts).with("Input: #{DOWN_ARROW}, Activity: Creek_creek_buzz_buzz")
                @process[2] = @game.pulls_down_seezaw_starts_current(DOWN_ARROW)
                @process[2].should == START_CURRENT
            end
            it "should perform starts_current_pushes_grove activity which returns RIGHT_ARROW" do
                @output.should_receive(:puts).with("Input: #{START_CURRENT}, Activity: Buzz_buzz_pow_wallop")
                @process[3] = @game.starts_current_pushes_grove(START_CURRENT)
                @process[3].should == RIGHT_ARROW
            end
            it "sends a finishing message" do
                @output.should_receive(:puts).with('...Game finished.')
                @game.finish            
            end
        end
    end
end

gen.rb

require 'sinatra'
$buffer = ""

# Main class module
module ImpossibleMachine
    # Input and output constants processed by subprocesses. MUST NOT change.
    DOWN_ARROW = 1
    UP_ARROW = 2
    RIGHT_ARROW = 3
    REPEAT_ARROW = 4
    END_PROCESS = 5 
    START_CURRENT = 6

    class Game
        attr_reader :process, :output
        attr_writer :process, :output

        def initialize(output)
            @output = output
            puts "[#{@output}]"
        end

        # All the code/methods aimed at passing the RSpect tests are below.

        def start
            @output.puts'Welcome to the Impossible Machine!'
            @output.puts'Starting game...'
        end

        def lifts_lever_turns_wheel(input)
            @input = input
            @output.puts 'Input: 2, Activity: Heave_ho_squeek_squeek'
            return REPEAT_ARROW
        end

        def turns_tap_on_pulls_down_seesaw(input)
            @input = input
            @output.puts 'Input: 4, Activity: Drip_drip_creek_creek'
            return DOWN_ARROW
        end

        def pulls_down_seezaw_starts_current(input)
            @input = input
            @output.puts 'Input: 1, Activity: Creek_creek_buzz_buzz'
            return START_CURRENT
        end

        def starts_current_pushes_grove(input)
            @input = input
            @output.puts 'Input: 6, Activity: Buzz_buzz_pow_wallop'
            return RIGHT_ARROW
        end

        def finish
            @output.puts'...Game finished.'
        end
    end
end

# Main program

module ImpossibleMachine
    @process = []
    g = Game.new(STDOUT)

    # All code added to output the activity messages to the command line window is below.

    g.start
            @process[0] = g.lifts_lever_turns_wheel(2)
            @process[1] = g.turns_tap_on_pulls_down_seesaw(@process[0])
            @process[2] = g.pulls_down_seezaw_starts_current(@process[1])
            @process[3] = g.starts_current_pushes_grove(@process[2])
    g.finish
end

# Any sinatra code added to output the activity messages to a browser should be added below.



# End program    

【问题讨论】:

  • 查看 IO 和 StringIO:g = Game.new(my_special_io).
  • 你知道rspec是用来测试的,而Sinatra是一个web-server,它们不能在一起(除非你是测试sinatra,在这种情况下,没有浏览器...)

标签: ruby rspec tdd buffer stdout


【解决方案1】:

设法让它在下班后工作! 在顶部添加/调整为:

require 'stringio'
$buffer= StringIO.new 

在主程序中:

g = Game.new($buffer)
g.start
@process[0] = g.lifts_lever_turns_wheel(2)
etc......
g.finish
puts $buffer.string #this sends it to stdout

然后只需在底部添加 sinatra 编码,它也将使用 $buffer.string

可能不是最好或最聪明的方法,但它使用了他们想要的全局缓冲区并将其获取到 sinatra 和 cmd 行。

【讨论】:

  • 谢谢克莱尔!你是英雄
  • 出于兴趣,您的程序是交互式游戏还是只是将输出打印到浏览器?我只是没有看到这个应用程序的意义。
  • 我同意,我的只是打印输出。这是我唯一担心的,也许它需要是交互式的。我认为因为目的是为了 TDD,所以它不是必需的。
  • 我已经与 Nigel Beachem 澄清了这一点,只需要输出,不需要交互。
【解决方案2】:

我认为您可以在主程序中创建某种缓冲区对象并将其传递到游戏中,就像您传递 STDOUT 一样。然后你可以在游戏中调用传入的对象的write方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-20
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 2013-03-07
    相关资源
    最近更新 更多