سؤال

I'm in the early stages of trying to write some sensible Javascript. I want to namespace basically everything under the name of my application to avoid globals as much as possible, but still give me a way to access functions declared around the place. However, I don't want to be super verbose in my function definitions.

My ideal CoffeeScript would be something like this:

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

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

You get the picture. This way I avoid having to write MyApp.Module.submoduleMethod = -> every time I want to define a namespaced function properly - using @ and defining things within my class definition keeps things nice and short.

This is all going well until I want to split my functionality up into multiple CoffeeScript files. Then what I really want is something like this:

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

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

It doesn't seem like Sprockets can do this.

Is there a sensible way to require my CoffeeScript files in the right place in my container files? Or another way to approach writing modular code that is divided into separate files using CoffeeScript, Sprockets and Rails 3.1?

هل كانت مفيدة؟

المحلول

I have a module solution that I use in my code.

I define my modules like below

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

Amazing is available as

foo.bar.Amazing

implementation of the @module helper is

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

It's written up on the coffeescript website here.

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

نصائح أخرى

Simply keep module1.js as-is and make application.js look something like this:

//= require 'module1'

class @MyApp
  ...

  @Module1 = Module1

This will work because you've made Module1 a global (declaring class @Module1 is equivalent to writing @Module1 = class Module1, and @ points to window in that context), and within the class @MyApp body, @ points to the class itself.

If you want Module1 to only be a property of the global MyApp class after it's attached, you could add the line

delete window.Module1

Here's the modular pattern I use for managing coffeescript with sprockets (works with Rails 4 as well):

  # 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

One disadavantage of this approach is that you are exposing your objects on window. Adding a module loader or adopting some of the new es syntax around modules could be a nice alternative depending on your needs.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top