Как вы пишете DRY, модульный coffeescript со Sprockets в Rails 3.1?

Я нахожусь на ранней стадии, пытаясь написать здравый 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?

Ответы

Ответ 1

У меня есть модульное решение, которое я использую в своем коде.

Я определяю свои модули, как показано ниже

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

Удивительный доступен как

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], [])

Здесь он написан на веб-сайте coffeescript.

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

Ответ 2

Просто держите module1.js как есть и сделайте application.js выглядеть примерно так:

//= require 'module1'

class @MyApp
  ...

  @Module1 = Module1

Это будет работать, потому что вы сделали Module1 глобальным (объявление class @Module1 эквивалентно записи @Module1 = class Module1, а @ указывает на window в этом контексте) и внутри тела class @MyApp, @ указывает на сам класс.

Если вы хотите, чтобы Module1 был только свойством глобального класса MyApp после его присоединения, вы могли бы добавить строку

delete window.Module1

Ответ 3

Здесь модульный шаблон, который я использую для управления coffeescript со звездочками (также работает с 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 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 вокруг модулей может стать хорошей альтернативой в зависимости от ваших потребностей.