您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?

Posted

技术标签:

【中文标题】您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?【英文标题】:How do you write DRY, modular coffeescript with Sprockets in Rails 3.1? 【发布时间】:2011-10-12 13:23:09 【问题描述】:

我正处于尝试编写一些合理的 javascript 的早期阶段。我想基本上以我的应用程序名称命名所有内容,以尽可能避免全局变量,但仍然给我一种访问在该位置周围声明的函数的方法。但是,我不想在函数定义中过于冗长。

我理想的 CoffeeScript 应该是这样的:

class @MyApp
  @myClassMethod = ->
    console.log 'This is MyApp.myClassMethod()'

  class @Module1
    @moduleMethod = ->
      console.log 'This is MyApp.Module1.moduleMethod()'

你明白了。这样我就避免了每次想要正确定义命名空间函数时都必须编写 MyApp.Module.submoduleMethod = -> - 使用 @ 并在我的类定义中定义事物 使事情变得简洁明了。

这一切都很顺利,直到我想将我的功能拆分为多个 CoffeeScript 文件。那么我真正想要的是这样的:

// application.js
class @MyApp
  //= require 'module1'
  //= require 'module2'

// module1.js
class @Module1
  @moduleMethod = ->
    console.log 'This is STILL MyApp.Module1.moduleMethod()'

Sprockets 似乎无法做到这一点。

有没有一种明智的方法来要求我的 CoffeeScript 文件在我的容器文件中的正确位置?或者使用 CoffeeScript、Sprockets 和 Rails 3.1 编写模块化代码的另一种方法?

【问题讨论】:

我认为这个问题需要进一步调查——下面的答案还不够好,尤其是。由于coffeescript 的创建者已经删除了“简单模块”页面b/c,因此技术很差。 【参考方案1】:

只需保持 module1.js 原样,让 application.js 看起来像这样:

//= require 'module1'

class @MyApp
  ...

  @Module1 = Module1

这将起作用,因为您已将 Module1 设为全局(声明 class @Module1 等同于编写 @Module1 = class Module1,并且在该上下文中 @ 指向 window),并且在 class @MyApp 正文中, @ 指向类本身。

如果您希望Module1 在附加后成为全局MyApp 类的属性,则可以添加该行

delete window.Module1

【讨论】:

好主意!如果我的模块名称与页面上其他脚本中的名称冲突,仍然会有问题,对吧?我很挑剔,因为我正在编写可能会使用书签注入其他页面的代码。 啊,在那种情况下,我只需定义一个全局变量,然后将其他所有内容附加到它上面。为此,请翻转您的依赖顺序:在 application.js 中,需要 module1.js,在 module1.js 中,需要 myapp.js,以便首先定义全局 MyApp。然后你可以写class MyApp.Module... 我上面的回答处理了名称冲突问题。使用类很好,但它不像在 ruby​​ 中可以猴子补丁。它将清除任何先前定义的类。 ***.com/questions/6815957/… 解决了这个问题【参考方案2】:

我有一个在我的代码中使用的模块解决方案。

我像下面这样定义我的模块

@module "foo", ->
    @module "bar", ->
        class @Amazing
            toString: "ain't it"

Amazing 可作为

foo.bar.Amazing

@module 助手的实现是

window.module = (name, fn)->
  if not @[name]?
    this[name] = 
  if not @[name].module?
    @[name].module = window.module
  fn.apply(this[name], [])

这里的咖啡脚本网站上写着。

https://github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript

【讨论】:

感谢您的链接。知道如何扩展它以使其在多个文件中正常工作吗? 它确实适用于多个文件。这就是它的全部意义所在。你说的好是什么意思? 我的意思是不必在每个文件中定义所有父模块。不过,这可能没有我最初想象的那么烦人。 你把@module "foo", -> 代码放在哪里了?你能把它放在application.js中吗?我认为它需要一个 .coffee 扩展名... @bradgonesurfing:coffeescript 的创建者删除了链接 - 他显然认为它不太好......那么有没有合适的方法来组织 JS 文件?例如,我无法使用以前在断开的链接处给出的方法来定义要在整个“类”中使用的常量或“实例变量”......【参考方案3】:

这是我用来管理带有 sprockets 的咖啡脚本的模块化模式(也适用于 Rails 4):

  # utils.js.coffee

  class Utils
    constructor: ->

    foo: ->
      alert('bar!!!')

    # private methods should be prefixed with an underscore
    _privateFoo: ->
      alert('private methods should not be exposed')

  instance = new Utils()

  # only expose the methods you need to.
  # because this is outside of the class,
  # you can use coffee's sugar to define on window

  @utils = foo: instance.foo

  # otherscript.js.coffee 

  //= require utils
  class OtherScript
    constructor: ->
      @utils.foo()         # alerts bar!!!
      @utils._privateFoo() # undefined method error

这种方法的一个缺点是您将对象暴露在窗口上。根据您的需要,添加模块加载器或在模块周围采用一些新的 es 语法可能是一个不错的选择。

【讨论】:

以上是关于您如何在 Rails 3.1 中使用 Sprockets 编写干燥的模块化咖啡脚本?的主要内容,如果未能解决你的问题,请参考以下文章

导轨 3.1。如何防止 Rails 使用 CoffeeScript?

Rails 3.1 http 流式传输——js 在头部还是底部?

如何在rails 3.1中使用jquery-addresspicker jquery

如何在 Rails 3.1 中为 CoffeeScript 使用选项“--bare”?

如何在 Rails 3.1 应用程序中完全禁用 CoffeeScript?

如何在 SQLite3 和 Rails 3.1 中打开 REGEXP?