agt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +7 -0
  3. data/README.md +5 -0
  4. data/app/assets/javascripts/agt/config.coffee +9 -0
  5. data/app/assets/javascripts/agt/dom.coffee +12 -0
  6. data/app/assets/javascripts/agt/function.coffee +317 -0
  7. data/app/assets/javascripts/agt/geom/circle.coffee +338 -0
  8. data/app/assets/javascripts/agt/geom/cubic_bezier.coffee +37 -0
  9. data/app/assets/javascripts/agt/geom/diamond.coffee +241 -0
  10. data/app/assets/javascripts/agt/geom/ellipsis.coffee +141 -0
  11. data/app/assets/javascripts/agt/geom/linear_spline.coffee +56 -0
  12. data/app/assets/javascripts/agt/geom/matrix.coffee +240 -0
  13. data/app/assets/javascripts/agt/geom/mixins/geometry.coffee +171 -0
  14. data/app/assets/javascripts/agt/geom/mixins/intersections.coffee +150 -0
  15. data/app/assets/javascripts/agt/geom/mixins/path.coffee +145 -0
  16. data/app/assets/javascripts/agt/geom/mixins/proxyable.coffee +9 -0
  17. data/app/assets/javascripts/agt/geom/mixins/spline.coffee +329 -0
  18. data/app/assets/javascripts/agt/geom/mixins/surface.coffee +55 -0
  19. data/app/assets/javascripts/agt/geom/mixins/triangulable.coffee +112 -0
  20. data/app/assets/javascripts/agt/geom/point.coffee +454 -0
  21. data/app/assets/javascripts/agt/geom/polygon.coffee +119 -0
  22. data/app/assets/javascripts/agt/geom/quad_bezier.coffee +43 -0
  23. data/app/assets/javascripts/agt/geom/quint_bezier.coffee +42 -0
  24. data/app/assets/javascripts/agt/geom/rectangle.coffee +599 -0
  25. data/app/assets/javascripts/agt/geom/spiral.coffee +90 -0
  26. data/app/assets/javascripts/agt/geom/transformation_proxy.coffee +43 -0
  27. data/app/assets/javascripts/agt/geom/triangle.coffee +442 -0
  28. data/app/assets/javascripts/agt/impulse.coffee +105 -0
  29. data/app/assets/javascripts/agt/index.coffee +56 -0
  30. data/app/assets/javascripts/agt/inflector/inflection.coffee +21 -0
  31. data/app/assets/javascripts/agt/inflector/inflections.coffee +75 -0
  32. data/app/assets/javascripts/agt/inflector/inflector.coffee +235 -0
  33. data/app/assets/javascripts/agt/inheritance.coffee +132 -0
  34. data/app/assets/javascripts/agt/math.coffee +45 -0
  35. data/app/assets/javascripts/agt/mixins/activable.coffee +31 -0
  36. data/app/assets/javascripts/agt/mixins/aliasable.coffee +25 -0
  37. data/app/assets/javascripts/agt/mixins/alternate_case.coffee +72 -0
  38. data/app/assets/javascripts/agt/mixins/cloneable.coffee +71 -0
  39. data/app/assets/javascripts/agt/mixins/delegation.coffee +90 -0
  40. data/app/assets/javascripts/agt/mixins/disposable.coffee +7 -0
  41. data/app/assets/javascripts/agt/mixins/equatable.coffee +37 -0
  42. data/app/assets/javascripts/agt/mixins/formattable.coffee +52 -0
  43. data/app/assets/javascripts/agt/mixins/globalizable.coffee +175 -0
  44. data/app/assets/javascripts/agt/mixins/has_ancestors.coffee +47 -0
  45. data/app/assets/javascripts/agt/mixins/has_collection.coffee +107 -0
  46. data/app/assets/javascripts/agt/mixins/has_nested_collection.coffee +51 -0
  47. data/app/assets/javascripts/agt/mixins/memoizable.coffee +64 -0
  48. data/app/assets/javascripts/agt/mixins/parameterizable.coffee +101 -0
  49. data/app/assets/javascripts/agt/mixins/poolable.coffee +62 -0
  50. data/app/assets/javascripts/agt/mixins/sourcable.coffee +45 -0
  51. data/app/assets/javascripts/agt/mixins/state_machine.coffee +47 -0
  52. data/app/assets/javascripts/agt/net/router.coffee +165 -0
  53. data/app/assets/javascripts/agt/object.coffee +9 -0
  54. data/app/assets/javascripts/agt/particles/actions/base_action.coffee +7 -0
  55. data/app/assets/javascripts/agt/particles/actions/die_on_surface.coffee +14 -0
  56. data/app/assets/javascripts/agt/particles/actions/force.coffee +11 -0
  57. data/app/assets/javascripts/agt/particles/actions/friction.coffee +14 -0
  58. data/app/assets/javascripts/agt/particles/actions/live.coffee +9 -0
  59. data/app/assets/javascripts/agt/particles/actions/macro_action.coffee +13 -0
  60. data/app/assets/javascripts/agt/particles/actions/move.coffee +11 -0
  61. data/app/assets/javascripts/agt/particles/actions/null_action.coffee +9 -0
  62. data/app/assets/javascripts/agt/particles/counters/by_rate.coffee +17 -0
  63. data/app/assets/javascripts/agt/particles/counters/fixed.coffee +9 -0
  64. data/app/assets/javascripts/agt/particles/counters/null_counter.coffee +9 -0
  65. data/app/assets/javascripts/agt/particles/emission.coffee +35 -0
  66. data/app/assets/javascripts/agt/particles/emitters/null_emitter.coffee +7 -0
  67. data/app/assets/javascripts/agt/particles/emitters/path.coffee +10 -0
  68. data/app/assets/javascripts/agt/particles/emitters/ponctual.coffee +9 -0
  69. data/app/assets/javascripts/agt/particles/emitters/surface.coffee +10 -0
  70. data/app/assets/javascripts/agt/particles/initializers/explosion.coffee +19 -0
  71. data/app/assets/javascripts/agt/particles/initializers/life.coffee +16 -0
  72. data/app/assets/javascripts/agt/particles/initializers/macro_initializer.coffee +10 -0
  73. data/app/assets/javascripts/agt/particles/initializers/null_initializer.coffee +7 -0
  74. data/app/assets/javascripts/agt/particles/initializers/particle_sub_system.coffee +12 -0
  75. data/app/assets/javascripts/agt/particles/initializers/stream.coffee +20 -0
  76. data/app/assets/javascripts/agt/particles/mixins/randomizable.coffee +10 -0
  77. data/app/assets/javascripts/agt/particles/particle.coffee +32 -0
  78. data/app/assets/javascripts/agt/particles/sub_system.coffee +11 -0
  79. data/app/assets/javascripts/agt/particles/system.coffee +103 -0
  80. data/app/assets/javascripts/agt/particles/timers/instant.coffee +11 -0
  81. data/app/assets/javascripts/agt/particles/timers/limited.coffee +19 -0
  82. data/app/assets/javascripts/agt/particles/timers/null_timer.coffee +11 -0
  83. data/app/assets/javascripts/agt/particles/timers/unlimited.coffee +9 -0
  84. data/app/assets/javascripts/agt/particles/timers/until_death.coffee +11 -0
  85. data/app/assets/javascripts/agt/promise.coffee +214 -0
  86. data/app/assets/javascripts/agt/random/random.coffee +100 -0
  87. data/app/assets/javascripts/agt/random/seeds/lagged_fibonnacci.coffee +53 -0
  88. data/app/assets/javascripts/agt/random/seeds/linear.coffee +16 -0
  89. data/app/assets/javascripts/agt/random/seeds/linear_congruential.coffee +23 -0
  90. data/app/assets/javascripts/agt/random/seeds/math_random.coffee +9 -0
  91. data/app/assets/javascripts/agt/random/seeds/mersenne_twister.coffee +42 -0
  92. data/app/assets/javascripts/agt/random/seeds/no_random.coffee +12 -0
  93. data/app/assets/javascripts/agt/random/seeds/paul_houle.coffee +19 -0
  94. data/app/assets/javascripts/agt/signal.coffee +272 -0
  95. data/app/assets/javascripts/agt/sprites/animation.coffee +13 -0
  96. data/app/assets/javascripts/agt/sprites/sprite.coffee +30 -0
  97. data/app/assets/javascripts/agt/widgets/hash.coffee +36 -0
  98. data/app/assets/javascripts/agt/widgets/widgets.coffee +194 -0
  99. data/app/assets/javascripts/agt/widgets/widgets/checked_input.coffee +7 -0
  100. data/app/assets/javascripts/agt/widgets/widgets/focus_bubbling.coffee +15 -0
  101. data/lib/agt.rb +8 -0
  102. data/lib/agt/version.rb +5 -0
  103. metadata +173 -0
@@ -0,0 +1,132 @@
1
+
2
+ # Internal: For a given function on an object it will find the property
3
+ # name and its kind (value/getter/setter).
4
+ findCaller = (caller, proto) ->
5
+ keys = Object.keys proto
6
+
7
+ for k in keys
8
+ descriptor = Object.getPropertyDescriptor proto, k
9
+
10
+ if descriptor?
11
+ return {key: k, descriptor, kind: 'value'} if descriptor.value is caller
12
+ return {key: k, descriptor, kind: 'get'} if descriptor.get is caller
13
+ return {key: k, descriptor, kind: 'set'} if descriptor.set is caller
14
+ else
15
+ return {key: k} if proto[k] is caller
16
+
17
+ {}
18
+
19
+ unless Object::super?
20
+ # Public: Gives access to the super method of any
21
+ Object.defineProperty Object.prototype, 'super', {
22
+ enumerable: false
23
+ configurable: true
24
+ value: (args...) ->
25
+ # To define which function to use as super when
26
+ # calling the `this.super` method we need to know which
27
+ # function is the caller.
28
+ caller = arguments.caller ? @super.caller
29
+ if caller?
30
+ # When the caller has a `__super__` property, we face
31
+ # a mixin method, we can access the `__super__` property
32
+ # to retrieve its super property.
33
+ if caller.__super__?
34
+ value = caller.__super__[caller.__included__.indexOf @constructor]
35
+
36
+ # The `this.super` method can be called only if the super
37
+ # is a function.
38
+ if value?
39
+ if typeof value is 'function'
40
+ value.apply(this, args)
41
+ else
42
+ throw new Error "The super for #{caller._name} isn't a function"
43
+ else
44
+ throw new Error "No super method for #{caller._name}"
45
+
46
+ # Without the `__super__` property we face a method declared
47
+ # in the including class and that may redefine a method from
48
+ # a mixin or a parent.
49
+ else
50
+ # The name of the property that stores the caller is retrieved.
51
+ # The `kind` variable is either `'value'`, `'get'`, `'set'`
52
+ # or `'null'`. It will be needed to find the correspondant
53
+ # super method in the property descriptor.
54
+ {key, kind} = findCaller caller, @constructor.prototype
55
+
56
+ # If the key is present we'll try to get a descriptor on the
57
+ # `__super__` class property.
58
+ if key?
59
+ desc = Object.getPropertyDescriptor @constructor.__super__, key
60
+
61
+ # And if a descriptor is available we get the function
62
+ # corresponding to the `kind` and call it with the arguments.
63
+ if desc?
64
+ value = desc[kind].apply(this, args)
65
+
66
+ # Otherwise, the value of the property is simply called.
67
+ else
68
+ value = @constructor.__super__[key].apply(this, args)
69
+
70
+ return value
71
+
72
+ # And in other cases an error is raised.
73
+ else
74
+ throw new Error "No super method for #{caller.name || caller._name}"
75
+ else
76
+ throw new Error "Super called with a caller"
77
+
78
+ }
79
+
80
+ # Public:
81
+ Object.defineProperty Function.prototype, 'super', {
82
+ enumerable: false
83
+ configurable: true
84
+ value: (args...) ->
85
+ caller = arguments.caller or @super.caller
86
+ if caller?
87
+ if caller.__super__?
88
+ value = caller.__super__[caller.__included__.indexOf this]
89
+
90
+ if value?
91
+ if typeof value is 'function'
92
+ value.apply(this, args)
93
+ else
94
+ throw new Error "The super for #{caller._name} isn't a function"
95
+ else
96
+ throw new Error "No super method for #{caller._name}"
97
+
98
+ else
99
+ # super method in the property descriptor.
100
+ {key, kind} = findCaller caller, this
101
+
102
+ reverseMixins = []
103
+ reverseMixins.unshift m for m in @__mixins__
104
+
105
+ # If the key is present we'll try to get a descriptor on the
106
+ # `__super__` class property.
107
+ if key?
108
+ for m in reverseMixins
109
+ if m[key]?
110
+ mixin = m
111
+ break
112
+
113
+ desc = Object.getPropertyDescriptor mixin, key
114
+
115
+ # And if a descriptor is available we get the function
116
+ # corresponding to the `kind` and call it with the arguments.
117
+ if desc?
118
+ value = desc[kind].apply(this, args)
119
+
120
+ # Otherwise, the value of the property is simply called.
121
+ else
122
+ value = mixin[key].apply(this, args)
123
+
124
+ return value
125
+
126
+ # And in other cases an error is raised.
127
+ else
128
+ throw new Error "No super class method for #{caller.name || caller._name}"
129
+ else
130
+ throw new Error "super called without a caller"
131
+
132
+ }
@@ -0,0 +1,45 @@
1
+
2
+ Math.PI2 = Math.PI * 2
3
+ Math.PI_2 = Math.PI / 2
4
+ Math.PI_4 = Math.PI / 4
5
+ Math.PI_8 = Math.PI / 8
6
+
7
+ ### Public ###
8
+
9
+ Math.degToRad = (n) -> n * Math.PI / 180
10
+
11
+ Math.radToDeg = (n) -> n * 180 / Math.PI
12
+
13
+ Math.normalize = (value, minimum, maximum) ->
14
+ (value - minimum) / (maximum - minimum)
15
+
16
+ Math.interpolate = (normValue, minimum, maximum) ->
17
+ minimum + (maximum - minimum) * normValue
18
+
19
+ Math.deltaBelowRatio = (a, b, ratio=10000000000) -> Math.abs(a - b) < 1 / ratio
20
+
21
+ Math.map = (value, min1, max1, min2, max2) ->
22
+ Math.interpolate Math.normalize(value, min1, max1), min2, max2
23
+
24
+ # Returns true if the passed-in argument can be casted to a number.
25
+ #
26
+ # Math.isFloat 0.245 # true
27
+ # Math.isFloat '12' # true
28
+ # Math.isFloat 'foo' # false
29
+ Math.isFloat = (floats...) ->
30
+ return false for float in floats when isNaN parseFloat float
31
+ true
32
+
33
+ Math.isInt = (ints...) ->
34
+ return false for int in ints when isNaN parseInt int
35
+ true
36
+
37
+ # Returns the passed-in arguments casted into floats.
38
+ Math.asFloat = (floats...) ->
39
+ floats[i] = parseFloat n for n,i in floats
40
+ floats
41
+
42
+ # Returns the passed-in arguments casted into floats.
43
+ Math.asInt = (ints...) ->
44
+ ints[i] = parseInt n for n,i in ints
45
+ ints
@@ -0,0 +1,31 @@
1
+ namespace('agt.mixins')
2
+ # Public: The `Activable` mixin provides the basic interface for an activable
3
+ # widget. You can hook your own activation/deactivation routines by overriding
4
+ # the `activated` and `deactivated` methods.
5
+ #
6
+ # ```coffeescript
7
+ # class Dummy
8
+ # @include agt.mixins.Activable
9
+ #
10
+ # activated: ->
11
+ # # ...
12
+ #
13
+ # deactivated: ->
14
+ # # ...
15
+ # ```
16
+ #
17
+ # `Activable` instances are deactivated at creation.
18
+ class agt.mixins.Activable
19
+ active: false
20
+
21
+ # Public: Activates the instance.
22
+ activate: ->
23
+ return if @active
24
+ @active = true
25
+ @activated?()
26
+
27
+ # Public: Deactivates the instance.
28
+ deactivate: ->
29
+ return unless @active
30
+ @active = false
31
+ @deactivated?()
@@ -0,0 +1,25 @@
1
+ namespace('agt.mixins')
2
+ # Public: Provides class methods to deal with aliased methods and properties.
3
+ #
4
+ # ```coffeescript
5
+ # class Dummy
6
+ # @extend agt.mixins.Aliasable
7
+ #
8
+ # someMethod: ->
9
+ # @alias 'someMethod', 'someMethodAlias'
10
+ # ```
11
+ class agt.mixins.Aliasable
12
+
13
+ # Public: Creates aliases for the given `source` property of tthe current
14
+ # class prototype. Any number of alias can be passed at once.
15
+ #
16
+ # source - The {String} name of the aliased property
17
+ # aliases - A list of {String}s to use as aliases.
18
+ @alias: (source, aliases...) ->
19
+ desc = Object.getPropertyDescriptor @prototype, source
20
+
21
+ if desc?
22
+ Object.defineProperty @prototype, alias, desc for alias in aliases
23
+ else
24
+ if @prototype[ source ]?
25
+ @prototype[ alias ] = @prototype[ source ] for alias in aliases
@@ -0,0 +1,72 @@
1
+ namespace('agt.mixins')
2
+ # Public: The `AlternateCase` mixin add methods to convert the properties
3
+ # of a class instance to camelCase or snake_case.
4
+ #
5
+ # The methods are available on the class itself and should be called
6
+ # after having declared all the class members.
7
+ #
8
+ # For instance, given the class below:
9
+ #
10
+ # ```coffeescript
11
+ # class Dummy
12
+ # @extend agt.mixins.AlternateCase
13
+ #
14
+ # someProperty: 'foo'
15
+ # someMethod: ->
16
+ #
17
+ # @snakify()
18
+ # ```
19
+ #
20
+ # An instance will have both `someProperty` and `someMethod` as defined
21
+ # by the class, but also `some_property` and `some_method`.
22
+ #
23
+ # The alternative is also possible. Given a class that uses snake_case
24
+ # to declare its member, the `camelize` method will provides the camelCase
25
+ # alternative to the class.
26
+ class agt.mixins.AlternateCase
27
+
28
+ # Public: Converts all the prototype properties to snake_case.
29
+ @snakify: -> @convert 'toSnakeCase'
30
+
31
+ # Public: Converts all the prototype properties to camelCase.
32
+ @camelize: -> @convert 'toCamelCase'
33
+
34
+ # Public: Adds the specified alternatives of each properties on the
35
+ # current prototype. The passed-in argument is the name of the class
36
+ # method to call to convert the key string.
37
+ #
38
+ # alternateCase - The {String} name of the class method to use
39
+ # to convert.
40
+ @convert: (alternateCase) ->
41
+ for key,value of @prototype
42
+ alternate = @[alternateCase] key
43
+
44
+ descriptor = Object.getPropertyDescriptor @prototype, key
45
+
46
+ if descriptor?
47
+ Object.defineProperty @prototype, alternate, descriptor
48
+ else
49
+ @prototype[alternate] = value
50
+
51
+ # Public: Converts a string to `snake_case`.
52
+ #
53
+ # str - The {String} to convert.
54
+ #
55
+ # Returns a {String} in `snake_case` .
56
+ @toSnakeCase: (str) ->
57
+ str.
58
+ replace(/([a-z])([A-Z])/g, "$1_$2")
59
+ .split(/_+/g)
60
+ .join('_')
61
+ .toLowerCase()
62
+
63
+ # Public: Converts a string to `camelCase`.
64
+ #
65
+ # str - The {String} to convert.
66
+ #
67
+ # Returns a {String} in `camelCase`.
68
+ @toCamelCase: (str) ->
69
+ a = str.toLowerCase().split(/[_\s-]/)
70
+ s = a.shift()
71
+ s = "#{ s }#{w.replace /^./, (s) -> s.toUpperCase()}" for w in a
72
+ s
@@ -0,0 +1,71 @@
1
+ namespace('agt.mixins')
2
+ # Internal: Contains all the function that will instanciate a class
3
+ # with a specific number of arguments. These functions are all generated
4
+ # at runtime with the `Function` constructor.
5
+ build = (klass, args) ->
6
+ BUILDS = (
7
+ new Function( "return new arguments[0](#{
8
+ ("arguments[1][#{ j-1 }]" for j in [ 0..i ] when j isnt 0).join ","
9
+ });") for i in [ 0..24 ]
10
+ )
11
+
12
+ f = BUILDS[ if args? then args.length else 0 ]
13
+ f klass, args
14
+
15
+ # Public: A `Cloneable` object can return a copy of itself through its `clone`
16
+ # method.
17
+ #
18
+ # The `Cloneable` generator function produces a different mixin when called
19
+ # with or without arguments.
20
+ #
21
+ # When called without argument, the returned mixin creates a clone using
22
+ # a copy constructor (a constructor that initialize the current object
23
+ # with an object).
24
+ #
25
+ # ```coffeescript
26
+ # class Dummy
27
+ # @include agt.mixins.Cloneable()
28
+ #
29
+ # constructor: (options={}) ->
30
+ # @property = options.property or 'foo'
31
+ # @otherProperty = options.otherProperty or 'bar'
32
+ #
33
+ # instance = new Dummy
34
+ # otherInstance = instance.clone()
35
+ # # otherInstance = {property: 'foo', otherProperty: 'bar'}
36
+ # ```
37
+ #
38
+ # When called with arguments, the `clone` method will call the class
39
+ # constructor with the values extracted from the given properties.
40
+ #
41
+ # ```coffeescript
42
+ # class Dummy
43
+ # @include agt.mixins.Cloneable('property', 'otherProperty')
44
+ #
45
+ # constructor: (@property='foo', @otherProperty='bar') ->
46
+ #
47
+ # instance = new Dummy
48
+ # otherInstance = instance.clone()
49
+ # # otherInstance = {property: 'foo', otherProperty: 'bar'}
50
+ # ```
51
+ #
52
+ # properties - A list of {String} of the properties to pass in the constructor.
53
+ #
54
+ # Returns a {ConcreteCloneable} mixin configured with the passed-in arguments.
55
+ agt.mixins.Cloneable = (properties...) ->
56
+
57
+ # Public: The concrete cloneable mixin as created by the
58
+ # [Cloneable](../files/mixins/cloneable.coffee.html) generator.
59
+ class ConcreteCloneable
60
+
61
+ # Public: Returns a copy of this instance.
62
+ #
63
+ # When the mixin is configurated without any `properties` the cloned
64
+ # instance is passed directly as argument at the creation of the new
65
+ # instance.
66
+ #
67
+ # Returns an {Object}.
68
+ clone: -> new @constructor this
69
+
70
+ if properties.length > 0
71
+ ConcreteCloneable::clone = -> build @constructor, properties.map (p) => @[ p ]
@@ -0,0 +1,90 @@
1
+ namespace('agt.mixins')
2
+ # Public: The `Delegation` mixin allow to define properties on an object that
3
+ # proxy another property of an object stored in one of its property.
4
+ #
5
+ # ```coffeescript
6
+ # class Dummy
7
+ # @extend agt.mixins.Delegation
8
+ #
9
+ # @delegate 'someProperty', to: 'someObject'
10
+ #
11
+ # constructor: ->
12
+ # @someObject = someProperty: 'some value'
13
+ #
14
+ # instance = new Dummy
15
+ # instance.someProperty
16
+ # # 'some value'
17
+ # ```
18
+ class agt.mixins.Delegation
19
+
20
+ # Public: The `delegate` class method generates a property on the current
21
+ # prototype that proxy the property of the given object.
22
+ #
23
+ # The `to` option specify the property of the object accessed by
24
+ # the delegated property.
25
+ #
26
+ # The delegated property name can be prefixed with the name of the
27
+ # accessed property
28
+ #
29
+ # ```coffeescript
30
+ # class Dummy
31
+ # @extend agt.mixins.Delegation
32
+ #
33
+ # @delegate 'someProperty', to: 'someObject', prefix: true
34
+ # # delegated property is named `someObjectSomeProperty`
35
+ # ```
36
+ #
37
+ # By default, using a prefix generates a camelCase property name.
38
+ # You can use the `case` option to change that to a snake_case property
39
+ # name.
40
+ #
41
+ # ```coffeescript
42
+ # class Dummy
43
+ # @extend agt.mixins.Delegation
44
+ #
45
+ # @delegate 'some_property', to: 'some_object', prefix: true, case: 'snake'
46
+ # # delegated property is named `some_object_some_property`
47
+ # ```
48
+ #
49
+ # The `delegate` method accept any number of properties to delegate
50
+ # with the same options.
51
+ #
52
+ # ```coffeescript
53
+ # class Dummy
54
+ # @extend agt.mixins.Delegation
55
+ #
56
+ # @delegate 'someProperty', 'someOtherProperty', to: 'someObject'
57
+ # ```
58
+ #
59
+ # properties - A list of {String} of the properties to delegate.
60
+ # options - The delegation options {Object}:
61
+ # :to - The {String} name of the target property.
62
+ # :prefix - A {Boolean} indicating whether to prefix the created
63
+ # delegated property name with the target property name.
64
+ # :case - An optional {String} to define the case to use to generate
65
+ # a prefixed delegated property.
66
+ @delegate: (properties..., options={}) ->
67
+ delegated = options.to
68
+ prefixed = options.prefix
69
+ _case = options.case or agt.CAMEL_CASE
70
+
71
+ properties.forEach (property) =>
72
+ localAlias = property
73
+
74
+ # Currently, only `camel`, and `snake` cases are supported.
75
+ if prefixed
76
+ switch _case
77
+ when agt.SNAKE_CASE
78
+ localAlias = delegated + '_' + property
79
+ when agt.CAMEL_CASE
80
+ localAlias = delegated + property.replace /^./, (m) ->
81
+ m.toUpperCase()
82
+
83
+ # The `Delegation` mixin rely on `Object.property` and thus can't
84
+ # be used on IE8.
85
+ Object.defineProperty @prototype, localAlias, {
86
+ enumerable: true
87
+ configurable: true
88
+ get: -> @[ delegated ][ property ]
89
+ set: (value) -> @[ delegated ][ property ] = value
90
+ }