agt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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