编写扩展
Sinatra 包含一个 API,供扩展作者使用,以帮助确保为应用程序开发人员提供一致的行为。
背景
编写良好的扩展需要了解 Sinatra 的内部设计。本节将概述 Sinatra 设计核心中的类和习惯用法。
Sinatra 有两种不同的使用模式,扩展应该注意这些模式
-
“经典”风格,其中应用程序在主/顶层定义 - 大多数示例和文档都针对这种用法。经典应用程序通常是单文件、独立的应用程序,可以直接从命令行运行,或者使用最小的 rackup 文件运行。当经典应用程序需要扩展时,期望所有扩展功能都应该存在,而无需应用程序开发人员进行额外的设置(例如包含/扩展模块)。
-
“模块化”风格,其中
Sinatra::Base
被显式地子类化,并且应用程序在子类的范围内定义。这些应用程序通常作为库捆绑在一起,并在更大的基于 Rack 的系统中用作组件。模块化应用程序必须通过在应用程序类的范围内调用register ExtensionModule
来显式地包含任何所需的扩展。
大多数扩展都与这两种风格相关,但扩展作者必须注意确保扩展在每种风格下都能正常工作。扩展 API (Sinatra.register
和 Sinatra.helpers
) 提供给扩展作者,以帮助他们完成此任务。
重要:以下关于 Sinatra::Base
和 Sinatra::Application
的说明仅供背景参考 - 扩展作者无需直接修改这些类。
Sinatra::Base
The Sinatra::Base
类为 Sinatra 应用程序中的所有评估提供上下文。顶层的 DSL 式内容存在于类范围内,而请求级内容存在于实例范围内。
应用程序在 Sinatra::Base
子类的类范围内定义。 “DSL”(例如,get
、post
、before
、configure
、set
等)只是一组在 Sinatra::Base
上定义的类方法。 扩展 DSL 是通过向 Sinatra::Base
或其子类添加类方法来实现的。 但是,基类不应使用 extend
扩展;为此任务提供了 Sinatra.register
方法(如下所述)。
请求在新的 Sinatra::Base
实例中进行评估 - 路由、前置过滤器、视图、助手和错误页面都共享相同的上下文。 默认的请求级助手方法集(例如,erb
、haml
、halt
、content_type
等)是在 Sinatra::Base
上或在包含在 Sinatra::Base
中的模块中定义的简单实例方法。 在请求级别提供新功能是通过向 Sinatra::Base
添加实例方法来实现的。
与 DSL 扩展一样,助手模块不应通过扩展作者使用 include
直接添加到 Sinatra::Base
中;为此任务提供了 Sinatra.helpers
方法(如下所述)。
Sinatra::Application
Sinatra::Application
类为经典风格应用程序提供默认的执行上下文。 它是一个简单的 Sinatra::Base
子类,它提供默认选项值和其他针对顶级应用程序定制的行为。 当运行经典风格应用程序时,所有 Sinatra::Application
公共类方法都会导出到顶级。
扩展规则
-
切勿直接修改
Sinatra::Base
。 您不应包含或扩展、更改选项值或以其他方式修改其行为。 模块化风格应用程序将使用register
方法在它们的子类中显式包含您的扩展。 -
切勿在您的扩展中
require 'sinatra'
。 您只需要require 'sinatra/base'
。 这样做的原因是require 'sinatra'
会触发经典风格 - 扩展永远不会触发经典风格。 -
尽可能使用下面描述的 API。您不应该直接包含或扩展模块,也不应该直接在核心 Sinatra 类上定义方法。下面的专用方法会为您处理所有这些操作。
-
扩展应该在
Sinatra
模块下的单独模块中定义。例如,一个添加基本身份验证原语的扩展可能被命名为Sinatra::BasicAuth
。
使用 Sinatra.helpers
扩展请求上下文
最常见的扩展类型是在路由、视图和辅助方法中添加方法的扩展。
例如,假设您想编写一个扩展,添加一个 h
方法,该方法可以转义保留的 HTML 字符(例如在其他流行的 Ruby Web 框架中找到的那些字符)。
对 Sinatra.helpers
的调用将模块包含在 Sinatra::Application
中,使模块中定义的所有方法都可用于经典风格的应用程序。在经典风格的应用程序中使用此扩展非常简单,只需需要扩展并使用新方法即可
另一方面,Sinatra::Base
子类必须使用 helpers
方法显式地需要并包含模块
使用 Sinatra.register
扩展 DSL(类)上下文
扩展还可以使用 Sinatra.register
方法扩展 Sinatra 的类级 DSL。这是一个添加 block_links_from
宏的扩展,该宏检查每个请求的引用器以查找应用程序提供的模式,并在检测到匹配时发送 403 Forbidden
响应
Sinatra.register
将模块中给出的所有公共方法作为类方法添加到 Sinatra::Application
上。它还处理在执行经典风格的应用程序时将公共方法导出到顶层。
经典风格的应用程序将按如下方式使用此扩展
模块化风格的应用程序必须在其 Sinatra::Base
子类中显式地注册扩展
设置选项和其他扩展设置
扩展可以通过在扩展模块上定义一个 registered
方法来定义选项、路由、前置过滤器和错误处理程序。 Module.registered
方法在扩展模块被添加到 Sinatra::Base
子类之后立即被调用,并且传递给该模块注册的类。
以下示例创建了一个非常简单的扩展,它添加了基本的会话身份验证支持。 添加了用户名和密码的选项,定义了登录的路由,并提供了用于确定用户是否已授权的辅助方法。
一个经典的应用程序将通过要求扩展库、覆盖选项和使用提供的辅助方法来使用此扩展。
模块化应用程序的不同之处在于它必须显式注册扩展模块。
构建和打包扩展
Sinatra 扩展应该构建为单独的库,并打包为 gem 或单个文件,这些文件可以包含在应用程序的 lib
目录中。 使用扩展的理想过程是安装 gem 并要求单个文件。
以下是一个典型的打包为 gem 的扩展的文件布局示例。
sinatra-fu
|-- README
|-- LICENSE
|-- Rakefile
|-- lib
| `-- sinatra
| `-- fu.rb
|-- test
| `-- spec_sinatra_fu.rb
`-- sinatra-fu.gemspec