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