《Ruby程序员修炼之道》(第2版)—第1章1.3节Ruby扩展和编程库

简介: 本节的要点并不是关于Ruby标准库的参考。曾在引言中解释过,本书的目标不是编写一本Ruby语言的参考文档,而是教会读者使用Ruby语言并掌握它,并最终拓宽视野。

本节书摘来自异步社区《Ruby程序员修炼之道》一书中的第1章,第1.3节Ruby扩展和编程库,作者【美】David A. Black(戴维 A. 布莱克),更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.3 Ruby扩展和编程库
本节的要点并不是关于Ruby标准库的参考。曾在引言中解释过,本书的目标不是编写一本Ruby语言的参考文档,而是教会读者使用Ruby语言并掌握它,并最终拓宽视野。

相应地,本节的目标是讲述扩展的工作方式,即如何使用Ruby运行这些扩展、它们之间技术实现的不同,并最终能让用户自己编写扩展和库文件的扩展架构。

随Ruby发布的扩展通常全部作为标准库来引用。标准库包括为不同项目和任务所提供的扩展,如数据库管理、网络、数学领域、XML处理等。标准库精密的结构每次改变,哪怕只有一点,也都要随着Ruby新版本而发布。使用最多、最广泛的库,已经证明了其存在的价值,所以通常都趋于稳定。

使用扩展和库的关键是require方法,与之密切相关的是load方法。这些方法让读者可以在运行时加载扩展,包括自己编写的扩展。我们将通过加载内置的扩展来学习它们并拓展我们的视野。

1.3.1 加载外部文件和扩展
可以手动把程序存储在单一文件中,但如果有成百上千行或者成千上万行的代码,这将是一种负担而不是优势。尽管如此,可以将程序分解为能运行的不同文件。在Ruby中使用require和load方法将会使得这一过程变得容易。这里先阐述load的使用,它是两个方法中设计得最简单的一个。

功能、扩展,还是库?

用户在运行时加载到程序中的程序代码有许多不同的名称。功能(feature)是最为抽象的,很少听到过有人说“请求一个功能”(requiring a feature,这里使用require)这样特殊的使用方式。库(library)是更为具体和通用的。它意味着存在一组真实的易于编程的代码,并能够被加载调用。扩展(extension)可以被任意可加载的附加库所引用,但是在Ruby中这通常意味着它们不是用Ruby而是用C语言编写而成的。如果要说正在编写的是Ruby扩展,就意味着已经假定那是用C语言编写的。
要试一下这个例子,需要将程序分写在两个文件中。第一个文件,名为loaddemo.rb,应该包含如下代码:

puts "This is the first (master) program file."
load "loadee.rb"
puts "And back again to the first file."

当它遇到load方法的调用时,Ruby就会加载第二个文件,这个文件名为loadee.rb,包含如下代码:

puts "> This is the second file."

这两个文件应该放在同一个目录下(假定存在示例代码目录)。在命令行中运行loaddemo.rb,可以看到如下输出结果:

This is the first (master) program file.
> This is the second file.
And back again to the first file.

这个结果可以追溯到执行文件的某一行,以及执行的顺序。

为了在loaddemo.rb中加载名为loadee.rb的文件,将它作为参数:

load "loadee.rb"

如果将要加载的文件就在工作目录中,Ruby将能够根据名称找到它。如果不是,Ruby将在加载路径(load path)中查找它们。

1.3.2 加载位于默认加载路径中的文件
Ruby解释器的加载路径是一系列目录,请求加载时,Ruby会在这些目录中搜索文件。可以使用$:(美元符号及冒号)检查加载目录下的这些子目录的名称,看到的结果取决于用户所使用的平台。在Mac OS X上,一个典型的加载目录如下(这个示例包含了.rvm的路径,它是Ruby版本管理器所决定的Ruby版本的路径):


3e5768cb6611cb1bd2055924d5453caa0de25c60

在你的电脑中,“ruby-2.1.0”左边的部分可能会有所不同,如“/usr/local/lib/”,但是子目录的基本模式都是一样的。当加载一个文件时,Ruby将会自上而下地在每一个子目录中搜索。

**注意
当前的工作目录,通常使用一个点(.)表示,这不会包含在加载目录中。加载命令的作用如前面所介绍,这只是一个特例。**

可以在load命令中使用代表上级目录的双点(..)符号导航到相对目录:

load "../extras.rb"

注意,如果在程序运行中改变当前的目录,相对目录的引用也将会改变。

**注意:
记住load是一个方法,在程序文件中,只有Ruby遇到它的时候才会执行。Ruby不会搜索整个文件去执行load命令。也就是说,当Ruby解释器遇到它的时候,它才会去寻找它要加载的文件。这意味着需要加载的文件名可以在运行时动态地决定。甚至可以在条件语句中包含一个load指令的调用,让它只有在条件为true的时候才会被执行。**

同时也可以强制指定load搜索一个完全限定的文件路径,而不管加载路径的内容。

load "/home/users/dblack/book/code/loadee.rb"

当然,这比起使用加载目录或者相对路径来说兼容性会差一些,但是这可能会很有用处,尤其是如果拥有一个字符串变量,其中包含一段绝对路径并想要加载它的时候。

load命令总是会加载所请求的文件,不论这个文件是否已经加载过。假如一个文件在几次加载过程中发生改变,那么最新版本的文件将优先使用并覆盖之前加载的版本。尤其是在irb会话中,当在编辑器中修改一个文件时,想要立刻测试修改的效果,这将非常有用。

另一个加载文件的方法是require,它同样也搜索默认的加载路径中的目录。但是require有一些load不具有的特点。

1.3.3 请求功能
load和require最大的不同在于,require就算调用多次也不会重新加载已经加载过的文件。Ruby会持续追踪已经被请求的那些文件而不会重复加载它们。

require比起load来说更为抽象。严格来说是不能请求一个文件的,而只能请求一个功能。一般来说,做到这一点甚至不用指定文件的扩展名。为了验证之前所述,将loaddemo.rb中的这一行进行修改,从

load "loadee.rb"
修改为

require "./loadee.rb"

当运行loaddemo.rb时,即使提供了需要加载的文件的完整文件名,得到的结果也可能与之前相同。

通过把loadee看作一个“功能”而不是一个文件,require对用Ruby编写的扩展和使用C语言写成的扩展都用一样的方式。另外,.rb扩展名的文件与其他扩展名为.so、.dll或者.bundle的文件使用方式也是一样的。

指定工作目录

require不能辨识出当前的工作目录(.)。用户可以显式地指定它,例如:

require "./loadee.rb"

或者可以使用数组添加运算符(<<),把当前目录添加到加载路径当中。

$: << "."

这样,就不必在调用require的时候显式地指定工作目录了。

require "loadee.rb"

也可以给require指定完全限定的路径,和使用load一样,把文件或者功能加载进来。读者也可以混合使用该规则,例如,即使是将静态路径与路径末端更为抽象的语法功能混合使用,以下语法也是可以正常运行的,例如:

require "/home/users/dblack/book/code/loadee.rb"

尽管load很有用,尤其是当加载多于一个文件的时候,但是require是一个日常使用的技术,用于请求Ruby扩展和库,不论是标准库还是第三方库。与加载loadee文件相比,请求标准库的功能要简单得多,只使用require就可以请求想要的任何库文件。之后,扩展中新的类和方法都可以使用了。下面的例子中,给出了请求前后在irb会话中的不同。

>> "David Black".scanf("%s%s")
NoMethodError: undefined method `scanf' for "David Black":String   
>> require "scanf"  
=> true
>> "David Black".scanf("%s%s")
=> ["David", "Black"]  

第一次调用scanf的时候失败并报错。但是在调用了require之后,没有编程人员的介入,"David Black"这个字符串对象也响应了scanf消息。(在这个例子中,使用空格为隐式分隔符,用于把原字符串抽取为两个连续的字符串)

1.3.4 require_relative指令
require_relative是第三种加载文件的方式。这个指令会搜索相对于所在文件的目录来加载功能。因此在前一个例子中,可以这样:

require_relative "loadee"

这样就可以不用把当前目录加入加载路径中。当需要导航到某个本地目录结构中的时候,require_relative是一个便捷的方式,例如:

require_relative "lib/music/sonata"

接下来将对随Ruby发布的命令行工具进行一次测验,以此总结这一章所学到的知识。

相关文章
|
6月前
|
网络协议 Ruby
|
2月前
|
SQL 自然语言处理 安全
探索研究Ruby CGI 编程
【9月更文挑战第1天】
45 6
|
30天前
|
SQL 网络安全 UED
深入探索研究Ruby CGI 编程
【10月更文挑战第1天】
27 0
|
3月前
|
开发者 Android开发 UED
打造流畅应用:深入探索如何在Xamarin项目中选择并实现最佳UI/UX设计的实践指南
【8月更文挑战第31天】在数字化时代,UI/UX设计成为应用成功的关键。Xamarin以高效开发和强大兼容性著称,其设计理念“一次编写,处处运行”需充分适应多平台特性,提供一致体验。选择Xamarin.Forms或结合Xamarin.Native可实现跨平台UI设计;遵循各平台设计指南,保持布局一致性和简洁性;通过用户测试不断优化。最终,结合技术和用户需求,打造美观实用的应用,脱颖而出。
52 0
|
3月前
|
开发者 编解码
界面适应奥秘:从自适应布局到图片管理,Xamarin响应式设计全解析
【8月更文挑战第31天】在 Xamarin 的世界里,构建灵活且适应性强的界面是每位开发者的必修课。本文将带您探索 Xamarin 的响应式设计技巧,包括自适应布局、设备服务协商和高效图片管理,帮助您的应用在各种设备上表现出色。通过 Grid 和 StackLayout 实现弹性空间分配,利用 Device 类检测设备类型以加载最优布局,以及使用 Image 控件自动选择合适图片资源,让您轻松应对不同屏幕尺寸的挑战。掌握这些技巧,让您的应用在多变的市场中持续领先。
37 0
|
3月前
|
开发者 数据库 虚拟化
Xamarin 应用性能优化策略大揭秘,从代码到界面再到数据访问,全面提升应用性能,快来围观!
【8月更文挑战第31天】在 Xamarin 跨平台移动应用开发中,性能优化至关重要。代码优化是基础,应避免不必要的计算与内存分配,如减少循环中的对象创建及合理使用数据结构。界面设计上需注意简化布局、减少特效并启用虚拟化以提升响应速度。数据访问方面,优化数据库查询和网络请求可显著改善性能。Xamarin Profiler 等工具还可帮助开发者实时监控并优化应用表现,从而打造流畅高效的用户体验。
53 0
|
3月前
|
开发者 测试技术 Android开发
Xamarin 开发者的五大常见问题及解决方案:从环境搭建到性能优化,全面解析高效跨平台应用开发的技巧与代码实例
【8月更文挑战第31天】Xamarin 开发者常遇问题及解决方案覆盖环境搭建至应用发布全流程,助新手克服技术难关。首先需正确安装配置 Visual Studio 及 Xamarin 支持,设置 iOS/Android 测试环境。利用 Xamarin.Forms 和 XAML 实现高效跨平台开发,共享 UI 和业务逻辑代码。针对性能优化,采取减少 UI 更新、缓存计算结果等措施,复杂问题则借助 Xamarin Profiler 分析。
43 0
|
3月前
|
API 数据库 Ruby
Ruby自动化魔法:揭秘日常任务的脚本编程秘籍
【8月更文挑战第31天】使用Ruby编写自动化脚本是一种高效且直观的方式。首先确保已安装Ruby环境,然后创建`auto_script.rb`文件开始编写。Ruby语法简洁优雅,内置及第三方库丰富,便于处理文件操作、网络请求和数据库交互等任务。通过`FileUtils`可轻松复制、删除或移动文件;利用`net/http`库可与网络API交互;`whenever`库帮助定时执行任务;而`mail`库则方便发送邮件。Ruby的强大功能和活跃社区支持,使自动化任务变得简单有趣。
46 0
|
3月前
|
开发者 Ruby
揭秘Ruby编程的神秘面纱!零基础也能快速掌握,优雅代码从此刻开始编织梦想!
【8月更文挑战第31天】这篇文章是 Ruby 入门指南,适合编程初学者。通过简单的“Hello, World!”示例,你将领略 Ruby 的简洁与优雅。文章介绍了变量定义、流程控制及方法与模块的使用,帮助你快速掌握基础语法。Ruby 的强大功能和友好社区将使你的编程之旅更加愉快。立即开始实践,探索更多可能性!
49 0
|
3月前
|
开发者 Ruby
【揭秘Ruby编程奥秘】对象、类与方法背后的秘密:掌控核心概念,轻松玩转面向对象编程!
【8月更文挑战第31天】Ruby是一种纯面向对象的语言,几乎所有内容都是对象。本文通过具体示例介绍Ruby的核心概念:对象、类与方法。对象是基本单位,一切皆对象;类定义对象的属性和行为;方法是对象的行为,在类中定义;继承允许子类继承父类的属性和方法;封装隐藏对象内部状态;多态允许子类重写父类方法;模块可被多个类共享。掌握这些概念有助于编写高效、可维护的代码。
53 0