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,105 @@
1
+
2
+ # Defines a local `requestAnimationFrame` function using the snippets
3
+ # from [Paul Irish](http://paulirish.com/2011/requestanimationframe-for-smart-animating/).
4
+ g = global ? window
5
+ requestAnimFrame = g.requestAnimationFrame or
6
+ g.webkitRequestAnimationFrame or
7
+ g.mozRequestAnimationFrame or
8
+ g.oRequestAnimationFrame or
9
+ g.msRequestAnimationFrame or
10
+ -> g.setTimeout callback, 1000 / 60
11
+
12
+ # Public: Impulse is a custom signal whose purpose is to handle
13
+ # animations within an application.
14
+ #
15
+ # The `Impulse` signal has its own messages to dispatch.
16
+ #
17
+ # Impulse dispatch its messages on a regular basis, based
18
+ # on the `requestAnimationFrame` function.
19
+ class agt.Impulse extends agt.Signal
20
+ ### Public ###
21
+
22
+ # Returns a global unique instance to use as reference
23
+ # in a typical application
24
+ #
25
+ # Returns an {agt.Impulse}
26
+ @instance: -> @__instance__ ||= new Impulse
27
+
28
+ # Initialize the `Impulse` signal with a specific time scale.
29
+ # By default the `timeScale` is `1`, which means there's no scaling.
30
+ constructor:(@timeScale=1)->
31
+ super()
32
+
33
+ @running = false
34
+
35
+ # Impulse listeners are registered as any other signal listeners.
36
+ #
37
+ # ```coffeescript
38
+ # impulse.add (bias, biasInSeconds, time) ->
39
+ # ```
40
+ #
41
+ # listener - The listener {Function} to register, with the following
42
+ # signature:
43
+ # :bias - The duration {Number} of the last animation
44
+ # frame in milliseconds.
45
+ # :biasInSeconds - The duration {Number} of the last
46
+ # animation frame in seconds.
47
+ # :time - The current time {Number} at the moment of the call.
48
+ # context - The this {Object} for the listener.
49
+ # priority - The priority {Number}, the greater the priority, the sooner
50
+ # the listener will be called.
51
+ add:(listener, context, priority=0)->
52
+ super listener, context, priority
53
+
54
+ # By convention, the `Impulse` signal start running when the
55
+ # first listener is added.
56
+ @start() if @hasListeners() and not @running
57
+
58
+ # Impulse listeners are unregistered as any other signal listeners.
59
+ #
60
+ # listener - The {Function} to remove from this signal.
61
+ # context - The `this` {Object} that was registered with the listener.
62
+ remove:(listener, context)->
63
+ super listener, context
64
+
65
+ # The `Impulse` object automatically stop itself when it doesn't
66
+ # have a listener anymore.
67
+ @stop() if @running and not @hasListeners()
68
+
69
+ # {Delegates to: agt.Signal.hasListeners}
70
+ hasListeners:->
71
+ @listeners.length > 0
72
+
73
+ # Starts, or restarts the `Impulse`.
74
+ start:->
75
+ @running = true
76
+ @initRun()
77
+
78
+ # Stops the `Impulse`.
79
+ stop:->
80
+ @running = false
81
+
82
+ # Internal: Initializes the run of the `Impulse`. A request
83
+ # is made to the `requestAnimationFrame` that will
84
+ # call the `run` method each time.
85
+ initRun:->
86
+ @time = @getTime()
87
+ requestAnimFrame =>
88
+ @run()
89
+
90
+ # A running `Impulse` will dispatch various informations
91
+ # to its listeners each time the `run` method is called.
92
+ #
93
+ # The `initRun` is called at the end of the function if the impulse
94
+ # is always running in order to continue the animation.
95
+ run:->
96
+ if @running
97
+ t = @getTime()
98
+ s = ( t - @time ) * @timeScale
99
+
100
+ @dispatch s, s / 1000, t
101
+ @initRun()
102
+
103
+ # Internal: Helper method that return the current time.
104
+ getTime:->
105
+ new Date().getTime()
@@ -0,0 +1,56 @@
1
+ # The module bootstrap.
2
+ isCommonJS = typeof module isnt "undefined"
3
+
4
+ __namespaces__ = {}
5
+
6
+ if isCommonJS
7
+ module.exports = agt = {}
8
+ else
9
+ window.agt = agt = {}
10
+
11
+ namespace = (path) ->
12
+ return if __namespaces__[path]
13
+
14
+ __namespaces__[path] = true
15
+
16
+ originalPath = path
17
+ path = path.split('.')
18
+ root = path.shift()
19
+
20
+ obj = if isCommonJS
21
+ module.exports
22
+ else
23
+ window[root] ||= {}
24
+
25
+ for p in path
26
+ obj = obj[p] = obj[p] or {}
27
+
28
+ window.namespace if window?
29
+
30
+ agt.deprecated = (message) ->
31
+ parseLine = (line) ->
32
+ if line.indexOf('@') > 0
33
+ if line.indexOf('</') > 0
34
+ [m, o, f] = /<\/([^@]+)@(.)+$/.exec line
35
+ else
36
+ [m, f] = /@(.)+$/.exec line
37
+ else
38
+ if line.indexOf('(') > 0
39
+ [m, o, f] = /at\s+([^\s]+)\s*\(([^\)])+/.exec line
40
+ else
41
+ [m, f] = /at\s+([^\s]+)/.exec line
42
+
43
+ [o,f]
44
+
45
+ e = new Error()
46
+ caller = ''
47
+ if e.stack?
48
+ s = e.stack.split('\n')
49
+ [deprecatedMethodCallerName, deprecatedMethodCallerFile] = parseLine s[3]
50
+
51
+ caller = if deprecatedMethodCallerName
52
+ " (called from #{deprecatedMethodCallerName} at #{deprecatedMethodCallerFile})"
53
+ else
54
+ "(called from #{deprecatedMethodCallerFile})"
55
+
56
+ console.log "DEPRECATION WARNING: #{message}#{caller}"
@@ -0,0 +1,21 @@
1
+ namespace('agt.inflector')
2
+
3
+ # Public: The `Inflection` class represent a single inflection for the general
4
+ # case of pluralization, singularization and conversion to the past tense.
5
+ class agt.inflector.Inflection
6
+ ### Public ###
7
+
8
+ # Creates a new instance.
9
+ #
10
+ # match - The {RegExp} or {String} to match.
11
+ # replace - The replacement {String}.
12
+ constructor: (@match, @replace) ->
13
+ @match = ///^#{@match}$///i if typeof @match is 'string'
14
+
15
+ # Converts the passed-in {String} if it matches the inflection's {RegExp}.
16
+ #
17
+ # string - The {String} to convert.
18
+ #
19
+ # Returns a {String}.
20
+ inflect: (string) ->
21
+ string.replace(@match, @replace) if @match.test(string)
@@ -0,0 +1,75 @@
1
+
2
+ agt.inflector.config 'en', ->
3
+ @plural(/$/, 's')
4
+ @plural(/s$/i, 's')
5
+ @plural(/^(ax|test)is$/i, '$1es')
6
+ @plural(/(octop|vir)us$/i, '$1i')
7
+ @plural(/(octop|vir)i$/i, '$1i')
8
+ @plural(/(alias|status)$/i, '$1es')
9
+ @plural(/(bu)s$/i, '$1ses')
10
+ @plural(/(buffal|tomat)o$/i, '$1oes')
11
+ @plural(/([ti])um$/i, '$1a')
12
+ @plural(/([ti])a$/i, '$1a')
13
+ @plural(/sis$/i, 'ses')
14
+ @plural(/(?:([^f])fe|([lr])f)$/i, '$1$2ves')
15
+ @plural(/(hive)$/i, '$1s')
16
+ @plural(/([^aeiouy]|qu)y$/i, '$1ies')
17
+ @plural(/(x|ch|ss|sh)$/i, '$1es')
18
+ @plural(/(matr|vert|ind)(?:ix|ex)$/i, '$1ices')
19
+ @plural(/^(m|l)ouse$/i, '$1ice')
20
+ @plural(/^(m|l)ice$/i, '$1ice')
21
+ @plural(/^(ox)$/i, '$1en')
22
+ @plural(/^(oxen)$/i, '$1')
23
+ @plural(/(quiz)$/i, '$1zes')
24
+
25
+ @singular(/s$/i, '')
26
+ @singular(/(ss)$/i, '$1')
27
+ @singular(/(n)ews$/i, '$1ews')
28
+ @singular(/([ti])a$/i, '$1um')
29
+ @singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis')
30
+ @singular(/(^analy)(sis|ses)$/i, '$1sis')
31
+ @singular(/([^f])ves$/i, '$1fe')
32
+ @singular(/(hive)s$/i, '$1')
33
+ @singular(/(tive)s$/i, '$1')
34
+ @singular(/([lr])ves$/i, '$1f')
35
+ @singular(/([^aeiouy]|qu)ies$/i, '$1y')
36
+ @singular(/(s)eries$/i, '$1eries')
37
+ @singular(/(m)ovies$/i, '$1ovie')
38
+ @singular(/(x|ch|ss|sh)es$/i, '$1')
39
+ @singular(/^(m|l)ice$/i, '$1ouse')
40
+ @singular(/(bus)(es)?$/i, '$1')
41
+ @singular(/(o)es$/i, '$1')
42
+ @singular(/(shoe)s$/i, '$1')
43
+ @singular(/(cris|test)(is|es)$/i, '$1is')
44
+ @singular(/^(a)x[ie]s$/i, '$1xis')
45
+ @singular(/(octop|vir)(us|i)$/i, '$1us')
46
+ @singular(/(alias|status)(es)?$/i, '$1')
47
+ @singular(/^(ox)en/i, '$1')
48
+ @singular(/(vert|ind)ices$/i, '$1ex')
49
+ @singular(/(matr)ices$/i, '$1ix')
50
+ @singular(/(quiz)zes$/i, '$1')
51
+ @singular(/(database)s$/i, '$1')
52
+
53
+ @irregular('person', 'people')
54
+ @irregular('man', 'men')
55
+ @irregular('child', 'children')
56
+ @irregular('sex', 'sexes')
57
+ @irregular('move', 'moves')
58
+ @irregular('zombie', 'zombies')
59
+
60
+ @uncountable('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep', 'jeans ', 'police')
61
+
62
+ @pastTense /^(.*)$/,'$1ed'
63
+ @pastTense /e$/,'ed'
64
+ @pastTense /t$/,'ted'
65
+ @pastTense /g$/,'gged'
66
+ @pastTense /ight$/,'ought'
67
+ @pastTense "buy",'bought'
68
+ @pastTense "has",'had'
69
+ @pastTense "sell",'sold'
70
+ @pastTense "is",'was'
71
+ @pastTense "are",'were'
72
+ @pastTense "teach",'taught'
73
+ @pastTense "feel",'felt'
74
+ @pastTense "light",'lit'
75
+ @pastTense "find",'found'
@@ -0,0 +1,235 @@
1
+ namespace('agt.inflector')
2
+ # Public: The `Inflector` transform words from singular to plural
3
+ # and verbs from present to past. The `agt.inflector` package is an instance
4
+ # of the `Inflector` class with default inflections for english words and verbs.
5
+ #
6
+ # ```coffeescript
7
+ # agt.inflector.config 'fr', ->
8
+ # @plural /$/, 's'
9
+ # @plural /^(bij|caill|ch|gen|hib|jouj|p)ou$/i, '$1oux'
10
+ # @plural /^(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/i, 'aux'
11
+ #
12
+ # @singular /s$/i, ''
13
+ # @singular /oux$/i, 'ou'
14
+ # @singular /aux$/i, 'ail'
15
+ #
16
+ # @uncountable 'discours', 'secours', 'souris'
17
+ #
18
+ # @pastTense /^a$/i, 'eu'
19
+ # @pastTense /^est$/i, 'fut'
20
+ #
21
+ # agt.inflector.pluralize('fr', 'coup') # 'coups'
22
+ # agt.inflector.pluralize('fr', 'hibou') # 'hiboux'
23
+ # agt.inflector.pluralize('fr', 'discours') # 'discours'
24
+ #
25
+ # agt.inflector.singularize('fr', 'hiboux') # 'hibou'
26
+ # agt.inflector.singularize('fr', 'coups') # 'coup'
27
+ # ```
28
+ class agt.inflector.Inflector
29
+
30
+ ### Public ###
31
+
32
+ # Extends or defines the inflections for a given language.
33
+ #
34
+ # ```coffee
35
+ # inflector.config 'en', ->
36
+ # # ...
37
+ #
38
+ # inflector.config 'fr', ->
39
+ # # ...
40
+ #
41
+ # inflector.config 'de', ->
42
+ # # ...
43
+ # ```
44
+ #
45
+ # As the language is passed to the `config` function, the methods available
46
+ # inside the block doesn't require the `lang` argument as the `Inflector`
47
+ # methods does.
48
+ #
49
+ # lang - The language {String} to configurate.
50
+ # block - The configuration {Function} to call. The function is called
51
+ # with the inflector as the `this` object as well as the sole
52
+ # argument.
53
+ config: (lang, block) ->
54
+ scope =
55
+ plural: (m,r) => @plural(lang,m,r)
56
+ singular: (m,r) => @singular(lang,m,r)
57
+ irregular: (p,s) => @irregular(lang,p,s)
58
+ uncountable: (a...) => @uncountable(lang,a)
59
+ pastTense: (m,r) => @pastTense(lang,m,r)
60
+
61
+ block.call(scope, scope)
62
+
63
+ # Defines a pluralization inflection for the specified language.
64
+ #
65
+ # ```coffee
66
+ # inflector.plural 'fr', /$/, 's'
67
+ #
68
+ # inflector.plural 'fr', /(eu|eau|au)$/i, '$1x'
69
+ #
70
+ # inflector.plural 'fr', /^(bij|caill|ch|gen|hib|jouj|p)ou$/i, '$1oux'
71
+ # ```
72
+ #
73
+ # lang - The language {String} to configurate. Note that when inside
74
+ # a configuration block this parameter is automatically set.
75
+ # match - The {RegExp} or the {String} that match words. When a string
76
+ # is passed, the created regex is equivalent to `///^#{word}$///`.
77
+ # replace - The replacement {String}. Groups defined in the regex can be
78
+ # freely used.
79
+ plural: (lang, match, replace) ->
80
+ @default(lang, 'plural')
81
+
82
+ inflection = new agt.inflector.Inflection(match, replace)
83
+ @inflections[lang].plural.push(inflection)
84
+
85
+
86
+ # Defines a singularization inflection for the specified language.
87
+ #
88
+ # ```coffee
89
+ # inflector.singlular 'fr', /s$/, ''
90
+ #
91
+ # inflector.singlular 'fr', /^(eu|eau|au)x$/i, '$1'
92
+ #
93
+ # inflector.singlular 'fr', /oux$/i, 'ou'
94
+ # ```
95
+ #
96
+ # lang - The language {String} to configurate. Note that when inside
97
+ # a configuration block this parameter is automatically set.
98
+ # match - The {RegExp} or the {String} that match words. When a string
99
+ # is passed, the created regex is equivalent to `///^#{word}$///`.
100
+ # replace - The replacement {String}. Groups defined in the regex can be
101
+ # freely used.
102
+ singular: (lang, match, replace) ->
103
+ @default(lang, 'singular')
104
+
105
+ inflection = new agt.inflector.Inflection(match, replace)
106
+ @inflections[lang].singular.push(inflection)
107
+
108
+ # Defines an inflection for an irregular word which pluralization doesn't
109
+ # follow the general rules such as person and people in english.
110
+ #
111
+ # ```coffee
112
+ # inflector.irregular 'fr', 'ail', 'aulx'
113
+ # inflector.irregular 'fr', 'œuil', 'yeux'
114
+ # ```
115
+ #
116
+ # lang - The language {String} to configurate. Note that when inside
117
+ # a configuration block this parameter is automatically set.
118
+ # singular - The singular {String} for the irregular word.
119
+ # plural - The plural {String} for the irregular word.
120
+ irregular: (lang, singular, plural) ->
121
+ @default(lang, 'plural')
122
+ @default(lang, 'singular')
123
+
124
+ pluralInflection = new agt.inflector.Inflection(singular, plural)
125
+ singularInflection = new agt.inflector.Inflection(plural, singular)
126
+ @inflections[lang].singular.push(singularInflection)
127
+ @inflections[lang].plural.push(pluralInflection)
128
+
129
+ # Defines one or many uncountable words. Uncountable words have a single
130
+ # form and are always returned as is in both {::pluralize} and {::singularize}
131
+ # methods.
132
+ #
133
+ # ```coffee
134
+ # inflector.uncountable 'fr', ['discours', 'secours']
135
+ #
136
+ # inflector.config 'fr', ->
137
+ # @uncountable 'discours', 'secours'
138
+ # ```
139
+ #
140
+ # lang - The language {String} to configurate. Note that when inside
141
+ # a configuration block this parameter is automatically set.
142
+ # uncountables - The {Array} of uncountable {String}. When inside
143
+ # a configuration block, the uncountable words must be passed
144
+ # as a list of {String}.
145
+ uncountable: (lang, uncountables) ->
146
+ @default(lang, 'uncountable')
147
+
148
+ @inflections[lang].uncountable = @inflections[lang].uncountable.concat(uncountables)
149
+
150
+ # Defines an inflection to convert a verb from its present form to its past
151
+ # form.
152
+ #
153
+ # ```coffee
154
+ # inflector.pastTense 'fr', /e/i, 'é'
155
+ # inflector.pastTense 'fr', /est/i, 'était'
156
+ # ```
157
+ #
158
+ # lang - The language {String} to configurate. Note that when inside
159
+ # a configuration block this parameter is automatically set.
160
+ # match - The {RegExp} or the {String} that match words. When a string
161
+ # is passed, the created regex is equivalent to `///^#{word}$///`.
162
+ # replace - The replacement {String}. Groups defined in the regex can be
163
+ # freely used.
164
+ pastTense: (lang, match, replace) ->
165
+ @default(lang, 'past')
166
+
167
+ inflection = new agt.inflector.Inflection(match, replace)
168
+ @inflections[lang].past.push(inflection)
169
+
170
+ # Conversion Methods
171
+
172
+ # Returns the passed-in {String} in its pluralized form.
173
+ #
174
+ # string - The {String} to pluralize.
175
+ # lang - The language {String} to use.
176
+ #
177
+ # Returns a {String}.
178
+ pluralize: (string, lang='en') -> @inflect('plural', string, lang)
179
+
180
+ # Returns the passed-in {String} in its singularized form.
181
+ #
182
+ # string - The {String} to singularize.
183
+ # lang - The language {String} to use.
184
+ #
185
+ # Returns a {String}.
186
+ singularize: (string, lang='en') -> @inflect('singular', string, lang)
187
+
188
+ # Returns the passed-in {String} in its past form.
189
+ #
190
+ # string - The {String} to conjugate to the past.
191
+ # lang - The language {String} to use.
192
+ #
193
+ # Returns a {String}.
194
+ toPast: (string, lang='en') -> @inflect('past', string, lang)
195
+
196
+ ### Internal ###
197
+
198
+ # Realizes the inflection for the passed-in string based on the specified
199
+ # conversion mode.
200
+ #
201
+ # conversion - The {String} kind of conversion to apply.
202
+ # string - The {String} to convert.
203
+ # lang - The language {String} to use.
204
+ #
205
+ # Returns a {String}.
206
+ inflect: (conversion, string, lang='en') ->
207
+ result = string
208
+ return result if string is '' or string in @inflections[lang].uncountable
209
+
210
+ inflections = @inflections[lang][conversion]
211
+
212
+ return result if not inflections? or inflections.length is 0
213
+
214
+ reversed = []
215
+ reversed.unshift(o) for o in inflections
216
+
217
+ reversed.some (inflection) ->
218
+ res = inflection.inflect(string)
219
+ result = res if res?
220
+ res
221
+
222
+ result
223
+
224
+ # Defines a new collection on the `inflections` object for the specified
225
+ # `lang`.
226
+ #
227
+ # lang - The target language {String}.
228
+ # collection - The {String} name of the collection to create.
229
+ default: (lang, collection)->
230
+ @inflections ||= {}
231
+ @inflections[lang] ||= {}
232
+ @inflections[lang][collection] ||= []
233
+
234
+ agt.inflector = new agt.inflector.Inflector
235
+ agt.inflector.Inflector = agt.inflector.constructor