我在Ruby中编写了一个小应用程序,现在想为它添加一个简单的API,以允许其他应用程序对它运行一些基本查询。
我一直在看senatra,因为它看起来非常轻巧简单。但我怀疑,不是将sinatra添加到我的应用程序来提供API,我应该将应用程序编写为sinatra应用程序。
我现在的问题是我可以用一个简单的“你好!”站起来“瘦”的服务器。在其中的端点,通过在我添加到我的应用程序对象的模块中定义它,如下所示:
module ApMessageIoModule
require 'sinatra/base'
require 'thin'
def start_server
Thread::abort_on_exception
Thread.new do
ApiServer.run!
end
end
class ApiServer < Sinatra::Base
configure do
server.threaded = settings.threaded if server.respond_to? :threaded=
end
get "/" do
"Hello!"
end
end
end
通过调用start_server()方法,我可以将服务器作为后台线程启动。但是现在我有了端点,我想让它引用我已经添加模块的类中的方法。
那么如何访问封闭类的命名空间呢?
e.g。
我添加模块的类名为StateMachine,它有一个方法:
# Query the state table for a particular state
def query_status(flag)
execute_sql_query(
"select status from state where state_flag = '#{flag}';"
)[0][0]
end
如何在上面的“获取”路线中调用此方法?
我找到了另一篇与此相关的帖子 -
Accessing a class's containing namespace from within a module
但它有点高于我的头脑,我没有运气试图调整给出的代码示例。
为了试图澄清这一点,我有一个课程,在这里显示:
class StateMachine
# Query the state table for a particular state
def query_status(flag)
execute_sql_query(
"select status from state where state_flag = '#{flag}';"
)[0][0]
end
end
该类包含上面显示的模块ApMessageIoModule。
StateMachine类已经实例化,在我的单元测试中:
# Confirm that SM can load one of our modules
def test_it_loads_user_modules
sm = StateMachine.new
sm.include_module('ApMessageIoModule')
sm.start_server
sleep(600)
sm.stop_server
assert_equal(sm.test_method, 'Test String')
end
我目前在那里有一个长时间的睡眠,允许我通过在浏览器中转到端点来手动确认服务器已启动。这样做会向我显示端点上预期的Hello消息。
查询状态方法与已创建的基础sqlite3数据库进行对话,并通过StateMachine的初始化方法调用的各种方法进行填充。为简洁起见,此处未显示。
所以我想做的是在ApMessageIoModule模块中的ApiServer类中调用StateMachine实例中的方法,如果这是有道理的。
实际上我认为这个便笺会更清晰:
require 'sinatra/base'
require 'thin'
module MyInclude
class SinatraServer < Sinatra::Base
get '/' do
test_method # This call fails with message shown below
end
get '/exit' do
exit!(0)
end
end
def startup
Thread.new do
SinatraServer.run!
end
end
end
class TopLevel
include MyInclude
def test_method
puts "TEST"
end
end
tl = TopLevel.new
tl.startup
sleep(600)
# Error message reads:
# NameError at /
# undefined local variable or method `test_method' for
# #<MyInclude::SinatraServer:0x00007fd002ac41d8>
# file: sinatra_server.rb location: block in <class:SinatraServer> line: 7
答案 0 :(得分:0)
你的query_status
是一个纯函数,它不依赖任何东西。将它放入完全分离的模块中,使其成为模块功能,并从任何地方将其称为模块功能:
module Helpers
def query_status(flag)
...
end
module_function :query_status
end
现在位于get
:
get "/" do
"Hello, " + Helpers.query_status('yes')
end
回答所述问题:由于此函数不会干扰任何数据(是纯函数),因此将其设为ApiServer
的类级函数,并通过它的名称来调用它:
class ApiServer < Sinatra::Base
def self.query_status(flag)
flag.to_s
end
get "/" do
"Hello, " + query_status('yes')
end
end