构建自己的MVC框架(Ruby语言实现)-- 第一章 从零到“它工作了!”

简介: 构建自己的MVC框架(Ruby语言实现)-- 第一章 从零到“它工作了!”

1. 从零到“它工作了!”

既然我们已经安装好了,到了开始构建的时候了。像Rails一样,你的框架将是一个gem(Ruby 的库),gem就像其他语言的库,可以包含、引用。整本书中,我们的框架的名字都是“Rules” ,就像“Ruby on Rails”。

开垦“荒地”

首先创建一个新的、空的 gem

$ bundle gem rulers
      create  rulers/Gemfile
      create  rulers/Rakefile
      create  rulers/LICENSE.txt
      create  rulers/README.md
      create  rulers/.gitignore
      create  rulers/rulers.gemspec
      create  rulers/lib/rulers.rb
      create  rulers/lib/rulers/version.rb
Initializating git repo in src/rulers”

rulers是我们创建的gem(库),我们可以在自动生成的rulers.gemspec文件里定义它所需的其他依赖 。使用你喜欢的文本编辑器里打开这个文件。你可以给你的gem起个你喜欢的名字,gem的功能描述 等等。你可以像这样自定义多个部分:

# rulers.gemspec
gem.name    = "rulers"
gem.version = Rulers::VERSION
gem.authors = ["Singleton Ruby-Webster"]
gem.email       = ["webster@singleton-rw.org"]
gem.homepage    = ""
gem.summary     = %q{A Rack-based Web Framework}
gem.description = %q{A Rack-based Web Framework,
                     but with extra awesome.}

按照惯例,摘要(summary)和描述(description)差不多,就是更短一些。摘要通常只有一样,然而描述有时会长达4-5行。

记住一定要把这个文件里“FIXME”和“TODO”这样的字符替换掉,“gem build”不喜欢它们,而且它们对用户也不友好。

你需要在底部添加依赖库。它们可能和下面的内容差不多:

gem.add_development_dependency "rspec"
gem.add_runtime_dependency "rest-client"
gem.add_runtime_dependency "some_gem", "1.3.0"
gem.add_runtime_dependency "other_gem", "> 0.8.2”

每一行添加一个运行时依赖(在运行gem的时候需要)或者开发时需要的依赖(在开发或测试 的时候用到的gem)。目前,只需添加下面的一行:

gem.add_runtime_dependency "rack"

完整的rulers.gemspec文件如下:

# rulers.gemspec (此为文件名,不需要复制这行,下同)
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'rulers/version'
Gem::Specification.new do |spec|
  spec.name          = "rulers"
  spec.version       = Rulers::VERSION
  spec.authors       = ["your_name"]
  spec.email         = ["your_name@example.com"]
  spec.summary       = '基于Rack的类Rails的框架'
  spec.description   = %q{基于Rack的简单Web框架,但是额外酷!}
  spec.homepage      = "http://rebuilding-rails.com"
  spec.license       = "MIT"
  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
  # delete this section to allow pushing this gem to any host.
  if spec.respond_to?(:metadata)
    spec.metadata['allowed_push_host'] = 'http://mygemserver.com'
  else
    raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
  end
  spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]
  spec.add_development_dependency "bundler", "~> 1.10"
  spec.add_development_dependency "rake", "~> 10.0"
end

rack也是一个gem,是你的框架和Ruby应用程序服务器,例如Mongrel、Thin、Lighttpd、Passenger、WEBrick或Unicorn之间的接口。应用服务器是特殊类型的网页服务器,运行服务器程序,通常是用Ruby写的。在真实的生产环境,会在应用程序服务器前再运行像Apache或者NGinX这样的网页服务器。但是在开发环境我只运行应用程序服务器,其他的都不运行。幸运的是,应用程序服务器作为网页服务器效果也还不错。

我们会在控制器那章覆盖更多Rack的细节,然后在中间件(Middleware)再次覆盖一部分。现在你只需要知道Ruby通过Rack把HTTP请求变成在你的服务器上运行的代码。

修改lib/rulers/version.rb文件,将‘0.1.0’改为‘0.1.1’。

让我们打包你的gem(译者注:Ruby是动态语言,不需要编译),然后安装它:

$ gem build reulers.gemspec
$ gem install rulers-0.0.1.gem

最终我们将从开发目录使用Bundler的技巧来使用你的gem。但是现在我们只是用简单的方法 来安装它。知道完成一个任务最简单的方法总是好的--当聪明的技巧不起作用的适合,你可 以回头使用它。

Hello World,或多或少

Rails就像你刚才打包的,但是它运行的是什么程序?我们将从一个很简单的app开始,你可以提交最爱的名言,用户可以给它们打分。Rails会为这个任务使用生成器(“rails new best_quotes"),但是我们将手动构建。

创建一个目录和一些子目录:

$ mkdir best_quotes
$ cd best_quotes
$ git init
Initialized empty Git repository in src/best_quotes/.git/
$ mkdir config
$ mkdir app”

你也想确定使用你的库。添加Gemfile:

# best_quotes/Gemfile
source 'https://ruby.taobao.org/'
gem 'rulers' #你创建的gem

然后运行“bundle install”来创建Gemfile.lock,确保所有的依赖都可以使用。

我们先构建一个小小的Rack程序。创建config.ru文件:

#best_quotes/config.ru
run proc {
  [200, {'Content-Type' => 'text/html'},
   ['Hello, World!']]
}

Rack的run意味着 对每个请求去调用这个对象。在这里,这个 proc 返回成功(200)和 Hello, world! 以及HTTP header来确保浏览器能正常显示HTML。

既然你现在已经有了个简单的可以显示Hello, world! 的 APP, 我们现在通过命令行来启动它:

$ rackup -p 3001

你应该能看到 “Hello, world!”。它来自于 config.ru 文件。

(无法启动rackup? 确定一下安装Ruby的时候是否PATH环境变量是否添加了gem的目录,也可以下载一下Ruby版本管理工具rvmrbenv 来帮你完成这些事情。)

使用Rack创建Rulers

在你的Rulers的目录,打开lib/rulers.rb。修改如下:

# rulers/lib/rulers.rb
requrie 'rulers/version'
module Rulers
  class Application
    def call(env)
      [200, {'Content-Type' => 'text/html'},
        ['Hello from Ruby on Rulers']]
    end
  end
end

我们重新打包、安装一下rulers

$ gem build rulers.gemspec
$ gem install rulers-0.0.1.gem

现在切换到你应用程序目录best_quotes:

现在你可以使用Rulers::Application类了。在config目录下新建文件config/application.rb,然后添加以下代码:

# best_quotes/config/application.rb
require 'rulers'
module BestQuotes
  class Application < Rulers::Application
  end
end

BestQuotes module使用了你的Rulers框架,当你使用它的时候会显示Hello from Ruby on Rulers。为了使用它,打开你的config.ru,然后修改如下:

require './config/application'
run BestQuotes::Application.new

现在当你在命令行输入:$ rackup -p 3001

然后在浏览器输入http://localhost:3001,你应该看到Hello from Ruby on Rulers!

你已经用你自己的框架创建了一个应用程序!

复习

在这章,你创建了一个可重复使用的Ruby库,也就是gem,然后你把你自己写gem包含进示例应用程序。你也建立了一个简单的Rack程序,你可以使用Rackup文件,即config.ru来创建。你已经学到了Rack的基本用法,还把这些东西连接起来让它们工作。

从这里开始,你将逐渐添加一些新东西进去。但是这章是唯一的一次从白板开始,从什么也 没有到有一点功能。

给自己敬个礼吧。

在Rails里

默认情况下,Rails包含不止一个,而是五个可以复用的gem。真正的Railsgem仅有很少的代码。相反,它分发给其他的gem来做具体实现。Rails本身只是把它们连接在一起。

Rails允许你自定义各种组件, 比如你可以使用不同的ORM,不同的测试库,不同的Ruby模板库或者不同的Javascript库。所以下面的描述对于由程序员严重自定义的Rails APP来说不一定准确。不过对于大部分情况下的Rails APP来说一般都适用。

下面是一些基本的rails gem -- 没有其他依赖和库,只是rails本身基本的一部分内容。

  • ActiveSupport是一个功能扩展库,它里面的方法不是专为Rails设计的。你会看见 一些不是Rails的库里也使用了ActiveSupport。ActiveSuppot包含了一些像Rails怎么变换单 词的单复数,或怎么把驼峰(CamelCase)名称转换成蛇形(snack_case)名称。它也包括了 比Ruby标准库更加丰富的时间和日期支持。
  • ActiveModel主要处理model,或者其他语言所说的Entity。它并不是一个针对数据库的实现。
  • 例如,假如你想要某个模型的URL,ActiveRecord也可以帮你实现。它只是包装了许多不 同ActiveModel的实现来告诉Rails怎样使用他们。更宽泛的说,ActiveModel实现是ORM(见 ActiveRecord,下面提到),但是它也能让我们使用非关系型存储,像MongoDB,Redis, Memcached或者甚至只是本地机器存储。
  • ActiveRecord是一个对象-关系映射(ORM)。这意味着它在Ruby对象和SQL数据库表之间 相互映射。当你在Rails里从SQL数据库查询或者写入数据,你都是通过ActiveRecord。ActiveRecord也是ActiveModel的实例。ActiveRecord支持MySQL和SQLite、也支持JDBC、 Oracle、PostgreSQL和许多其他的关系型数据库。
  • ActionPack负责路由 - 输入的URL到Rails里的控制器(Controller)和动作(Action) 之间的映射。它也用来创建Rails 中的 controller和action,然后引导request遍历controller,以及action,然后渲染视 图view。这里中的一些功能,ActionPack通过Rack来实现。而视图渲染则是引入其他的外部的gem来渲染template, 比如用Eruby渲染.erb模板、Haml渲染.haml模板。ActionPack也处理action - 或以view为中心的功能,如view缓存。
  • ActionMailer 则用来发送邮件,尤其是基于模板的email。它具有你期望Rails email能具有的 功能,有控制器、动作、和“视图” - 对于email来是说基于文本的模板,不是普通的网页模板。

当然,Rails里也不是啥都有。

一些你在这章里构建的功能是在App里,不是在Rulers里。

继续向前,创建新的Rails 3应用 - 输入 rails new test_app

假如你看看config/application.rb,你会看见Rails 建立了一个Rails Application对象,非常像Rulers Application对象。

现在该是打开config目录,看看Rails Application默认生成了些什么的时候了。

你看到一些现在觉得更合理的代码了吗?

练习

练习1. 重新加载Rulers

让我们给Rulers框架添加一点调试代码。

# rulers/lib/rulers.rb
module Rulers
  class Application
    def call(env)
     `echo debug > debug.txt`;
     [200, {'Content-Type' => 'text/html'},
       ['Hello from Ruby on Rulers!']]
    end
  end
end

当这个运行时,它应该在best_quotes文件夹下创建一个名为debug.txt的文件,也就是你运 行rackup的那个目录。

试着重启你的服务器,刷新你的浏览器页面“http://localhost:3001”。但是你找不到debug 文件!

试试重新打包gem,然后重新安装它

$ gem build rulers
$ gem install rulers-0.0.1.gem

刷新浏览器。你仍看不见它。

最后,再次重启你的服务器,刷新浏览器。现在,你终于看见debug文件了。

Rails和Rulers都很难调试。在第三章我们将看到Bundler的:path选项,可以让我们调试容易 点。现在你需要重新安装gem和重启rack服务器来让新的Rulers代码执行。

这样当方便的方式行不通的时候,你也知道怎么用笨方法。

练习2. 你的库的库

你可以开始一个简单的可复用的库,就像ActiveSupport。当程序使用你的Rulers gem,然后require它(require rulers),程序会自动得到那个文件里所有方法。试试添加lib/rulsers/array.rb的文件, 然后加入以下代码:

# rulers/lib/array.rb
class Array
  def sum(start = 0)
    inject(start, &:+)
  end
end

你以前见过&:+吗?它是个有趣的技巧。:+意思是“symbol +”;就像“:foo”,意思是“symbol foo”。“&”意思是“当作块传递”-- 在圆括号里的代码块通常跟在后面。所以你正把符号当作代码块 来传递。Ruby知道把符号转换为proc,然后调用它。当你用“加”的时候,你得到“把这些加 起来”。

现在,把require 'rulers/array'添加到lib/rulers.rb的顶部。它会在所有Rulers应用里包含它。

在你打包gem前,你需要进入rulers目录,运行

$ git add -A
$ $ gem build rulers
$ gem install rulers-0.0.1.gem

这是因为rulers.gemspec实际调用git来查找包含进你gem里的文件。你可以在rulers.gemspec文件里看到一行:

gem.files = `git ls-files`.split($/)

git ls-files仅仅显示git知道的文件 -- split只是为了得到输出的每一行。

假如你创建了一个新文件,确信你重新打包前运行了git add -A,否则你看不到它!

现在有了新的rulers/array.rb文件,任何包含了Rulers的程序都能通过 [1, 2, 37, 9].sum 的方式 得到数组的和。

继续,添加更多的那些使用你的框架的程序可能会有用的方法。

相关文章
|
8月前
|
前端开发 Java 数据库连接
Spring MVC 扩展和SSM框架整合
通过以上步骤,我们可以将Spring MVC扩展并整合到SSM框架中。这个过程包括配置Spring MVC和Spring的核心配置文件,创建控制器、服务层和MyBatis的Mapper接口及映射文件。在实际开发中,可以根据具体业务需求进行进一步的扩展和优化,以构建更加灵活和高效的企业级应用程序。
210 5
|
设计模式 前端开发 数据库
深入理解MVC设计模式:构建高效Web应用程序的基石
【7月更文挑战第4天】在软件工程领域,设计模式是解决常见问题的一系列经过验证的方法。其中,Model-View-Controller(MVC)设计模式自诞生以来,便成为了构建用户界面,特别是Web应用程序的黄金标准。MVC通过将应用程序逻辑分离为三个核心组件,提高了代码的可维护性、可扩展性和重用性。本文将深入探讨MVC设计模式的原理,并通过一个简单的代码示例展示其应用。
416 0
|
11月前
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
331 5
|
前端开发 安全 Java
技术进阶:使用Spring MVC构建适应未来的响应式Web应用
【9月更文挑战第2天】随着移动设备的普及,响应式设计至关重要。Spring MVC作为强大的Java Web框架,助力开发者创建适应多屏的应用。本文推荐使用Thymeleaf整合视图,通过简洁的HTML代码提高前端灵活性;采用`@ResponseBody`与`Callable`实现异步处理,优化应用响应速度;运用`@ControllerAdvice`统一异常管理,保持代码整洁;借助Jackson简化JSON处理;利用Spring Security增强安全性;并强调测试的重要性。遵循这些实践,将大幅提升开发效率和应用质量。
185 7
|
前端开发 Java
【案例+源码】详解MVC框架模式及其应用
【案例+源码】详解MVC框架模式及其应用
1103 0
|
监控 网络安全 持续交付
公司电脑管理软件结合 Ruby 语言的实践探索
在数字化办公时代, Ruby 语言以简洁灵活的特点, 成为公司电脑管理软件开发的新选择。通过示例代码展示了 Ruby 在获取系统信息、监控内存使用及远程管理方面的应用。Ruby 的灵活性与丰富库资源, 大大提升了管理效率与准确性, 为企业数字化管理带来新可能。
127 3
|
自然语言处理 Ruby
Ruby语言揭秘:如何轻松驾驭自然语言处理?
【8月更文挑战第31天】本文介绍了如何利用Ruby进行自然语言处理(NLP),包括安装`treat`库及其实现文本分词、词性标注和命名实体识别等基础任务的方法。通过示例代码,展示了Ruby在NLP领域的强大功能与灵活性,为初学者提供了一个友好且实用的入门指南。在信息爆炸的今天,掌握Ruby进行NLP处理的技能显得尤为重要。
112 0
|
测试技术 开发者 Ruby
Ruby领域特定语言(DSL)的神秘力量:如何让你的代码飞起来?
【8月更文挑战第31天】在软件开发领域,Ruby以简洁的语法和强大的表达能力著称,但面对复杂业务逻辑时,代码可能变得冗长难维护。此时,领域特定语言(DSL)成为解决问题的有效途径。DSL专为特定领域设计,使代码更贴近业务逻辑,提高可读性和可维护性。本文通过示例展示了如何在Ruby中开发DSL,包括使用解析器和宏功能创建一个简单的Web应用结构描述语言,并提出了定义清晰语法、避免滥用DSL等最佳实践,强调了测试与文档的重要性。
222 0
|
设计模式 存储 前端开发
MVC 框架的主要问题是什么?
【8月更文挑战第30天】
293 0
|
安全 前端开发 测试技术
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
151 0
下一篇
oss云网关配置