4

在 Ruby Gosu 中构建瓷砖游戏或模拟总是让我最终得到一个由他们的班级保存的所有可用瓷砖的列表。例如[Pipe, PipeJunktion, Box, Pump]等等。每个类都定义在几个单独的文件之一中,这是我从主程序中需要的。现在,每次我向游戏添加新图块时,我都必须自己将类添加到此列表中。我想知道是否有办法从文件中捕获所有加载类。

类似于以下内容:

allTiles = []
require_relative 'tiles.rb'.each_class {|class| allTiles << class}

会很方便。或者这可以通过某种方式用模块解决吗?

4

3 回答 3

2

你可以这样做:

Dir['tiles/*.rb'].each { |file| require file }

什么会从子文件夹中收集所有文件tiles并需要它。

在下一步中,按文件名加载所有类:

all_tiles = Dir['tiles/*.rb'].map do |file| 
  file_name = File.basename(x, '.*')
  camel_cased_name = file_name.split('_').collect(&:capitalize).join
  Object.const_get(camel_cased_name)
end

顺便说一句,在 Rails 中也可以这样做:

all_tiles = Dir['tiles/*.rb'].map do |file| 
  File.basename(x, '.*').camelize.constantize
end
于 2017-04-28T18:27:32.650 回答
2

检查文件添加了哪些类并不是一件容易或常见的事情。更好的方法是将所有的 tile 类放在一个命名空间下。由于可以重新打开类,因此可以将它们拆分为多个文件。

class Tiles
  class Pipe
    # ...
  end
end

class Tiles
  class Box
    # ...
  end
end

然后Tiles.constantscould 将返回一个符号数组:[:Pipe, :Box],并且可以用于使用Tiles.constants.map { |const| Tiles.const_get const }or获取类引用列表Tiles.constants.map &Tiles.method(:const_get)

如果出于某种原因,知道特定文件添加了哪些常量非常重要,则以下代码显示了一种方法:

constants1 = Object.constants
require "./tiles.rb"
constants2 = Object.constants
added_constants = constants2 - constants1

如果tiles.rb有 和 的类定义PipeBox那么added_constants就是[:Pipe, :Box]

这种方法的问题是可能会显示 gem 添加的常量,例如:

constants1 = Object.constants
require 'mechanize'
class Foo
end
constants2 = Object.constants
added_constants = constants2 - constants1

既然我打过电话require 'mechanize',这份added_constants名单就会很长,而且不仅仅包括Foo

于 2017-04-28T19:07:28.877 回答
0

我怀疑以下方法存在缺陷,但我会将其发布并邀请评论。

首先,使用ObjectSpace::each_object编译在创建任何自定义类之前存在的所有类的列表:

base_classes = ObjectSpace.each_object(Class).to_a

对于我的 Ruby (2.4.0) 版本,在 IRB 中,base_classes.size #=> 490. 现在用 's 等加载代码require。假设这会导致创建三个类:

class A; end
class B; end
class C; end

现在编译现在存在的所有类的列表并减去base_classes

ObjectSpace.each_object(Class).to_a - base_classes
  #=> [A, B, C]

这将返回一个由我的代码添加的类数组。

当然,这不会显示base_classes被我的代码覆盖的类或显示哪些类是由所需的 gem 定义的。

于 2017-04-29T07:33:23.927 回答