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.
- checksums.yaml +7 -0
- data/LICENSE.md +7 -0
- data/README.md +5 -0
- data/app/assets/javascripts/agt/config.coffee +9 -0
- data/app/assets/javascripts/agt/dom.coffee +12 -0
- data/app/assets/javascripts/agt/function.coffee +317 -0
- data/app/assets/javascripts/agt/geom/circle.coffee +338 -0
- data/app/assets/javascripts/agt/geom/cubic_bezier.coffee +37 -0
- data/app/assets/javascripts/agt/geom/diamond.coffee +241 -0
- data/app/assets/javascripts/agt/geom/ellipsis.coffee +141 -0
- data/app/assets/javascripts/agt/geom/linear_spline.coffee +56 -0
- data/app/assets/javascripts/agt/geom/matrix.coffee +240 -0
- data/app/assets/javascripts/agt/geom/mixins/geometry.coffee +171 -0
- data/app/assets/javascripts/agt/geom/mixins/intersections.coffee +150 -0
- data/app/assets/javascripts/agt/geom/mixins/path.coffee +145 -0
- data/app/assets/javascripts/agt/geom/mixins/proxyable.coffee +9 -0
- data/app/assets/javascripts/agt/geom/mixins/spline.coffee +329 -0
- data/app/assets/javascripts/agt/geom/mixins/surface.coffee +55 -0
- data/app/assets/javascripts/agt/geom/mixins/triangulable.coffee +112 -0
- data/app/assets/javascripts/agt/geom/point.coffee +454 -0
- data/app/assets/javascripts/agt/geom/polygon.coffee +119 -0
- data/app/assets/javascripts/agt/geom/quad_bezier.coffee +43 -0
- data/app/assets/javascripts/agt/geom/quint_bezier.coffee +42 -0
- data/app/assets/javascripts/agt/geom/rectangle.coffee +599 -0
- data/app/assets/javascripts/agt/geom/spiral.coffee +90 -0
- data/app/assets/javascripts/agt/geom/transformation_proxy.coffee +43 -0
- data/app/assets/javascripts/agt/geom/triangle.coffee +442 -0
- data/app/assets/javascripts/agt/impulse.coffee +105 -0
- data/app/assets/javascripts/agt/index.coffee +56 -0
- data/app/assets/javascripts/agt/inflector/inflection.coffee +21 -0
- data/app/assets/javascripts/agt/inflector/inflections.coffee +75 -0
- data/app/assets/javascripts/agt/inflector/inflector.coffee +235 -0
- data/app/assets/javascripts/agt/inheritance.coffee +132 -0
- data/app/assets/javascripts/agt/math.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/activable.coffee +31 -0
- data/app/assets/javascripts/agt/mixins/aliasable.coffee +25 -0
- data/app/assets/javascripts/agt/mixins/alternate_case.coffee +72 -0
- data/app/assets/javascripts/agt/mixins/cloneable.coffee +71 -0
- data/app/assets/javascripts/agt/mixins/delegation.coffee +90 -0
- data/app/assets/javascripts/agt/mixins/disposable.coffee +7 -0
- data/app/assets/javascripts/agt/mixins/equatable.coffee +37 -0
- data/app/assets/javascripts/agt/mixins/formattable.coffee +52 -0
- data/app/assets/javascripts/agt/mixins/globalizable.coffee +175 -0
- data/app/assets/javascripts/agt/mixins/has_ancestors.coffee +47 -0
- data/app/assets/javascripts/agt/mixins/has_collection.coffee +107 -0
- data/app/assets/javascripts/agt/mixins/has_nested_collection.coffee +51 -0
- data/app/assets/javascripts/agt/mixins/memoizable.coffee +64 -0
- data/app/assets/javascripts/agt/mixins/parameterizable.coffee +101 -0
- data/app/assets/javascripts/agt/mixins/poolable.coffee +62 -0
- data/app/assets/javascripts/agt/mixins/sourcable.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/state_machine.coffee +47 -0
- data/app/assets/javascripts/agt/net/router.coffee +165 -0
- data/app/assets/javascripts/agt/object.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/base_action.coffee +7 -0
- data/app/assets/javascripts/agt/particles/actions/die_on_surface.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/force.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/friction.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/live.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/macro_action.coffee +13 -0
- data/app/assets/javascripts/agt/particles/actions/move.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/null_action.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/by_rate.coffee +17 -0
- data/app/assets/javascripts/agt/particles/counters/fixed.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/null_counter.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emission.coffee +35 -0
- data/app/assets/javascripts/agt/particles/emitters/null_emitter.coffee +7 -0
- data/app/assets/javascripts/agt/particles/emitters/path.coffee +10 -0
- data/app/assets/javascripts/agt/particles/emitters/ponctual.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emitters/surface.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/explosion.coffee +19 -0
- data/app/assets/javascripts/agt/particles/initializers/life.coffee +16 -0
- data/app/assets/javascripts/agt/particles/initializers/macro_initializer.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/null_initializer.coffee +7 -0
- data/app/assets/javascripts/agt/particles/initializers/particle_sub_system.coffee +12 -0
- data/app/assets/javascripts/agt/particles/initializers/stream.coffee +20 -0
- data/app/assets/javascripts/agt/particles/mixins/randomizable.coffee +10 -0
- data/app/assets/javascripts/agt/particles/particle.coffee +32 -0
- data/app/assets/javascripts/agt/particles/sub_system.coffee +11 -0
- data/app/assets/javascripts/agt/particles/system.coffee +103 -0
- data/app/assets/javascripts/agt/particles/timers/instant.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/limited.coffee +19 -0
- data/app/assets/javascripts/agt/particles/timers/null_timer.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/unlimited.coffee +9 -0
- data/app/assets/javascripts/agt/particles/timers/until_death.coffee +11 -0
- data/app/assets/javascripts/agt/promise.coffee +214 -0
- data/app/assets/javascripts/agt/random/random.coffee +100 -0
- data/app/assets/javascripts/agt/random/seeds/lagged_fibonnacci.coffee +53 -0
- data/app/assets/javascripts/agt/random/seeds/linear.coffee +16 -0
- data/app/assets/javascripts/agt/random/seeds/linear_congruential.coffee +23 -0
- data/app/assets/javascripts/agt/random/seeds/math_random.coffee +9 -0
- data/app/assets/javascripts/agt/random/seeds/mersenne_twister.coffee +42 -0
- data/app/assets/javascripts/agt/random/seeds/no_random.coffee +12 -0
- data/app/assets/javascripts/agt/random/seeds/paul_houle.coffee +19 -0
- data/app/assets/javascripts/agt/signal.coffee +272 -0
- data/app/assets/javascripts/agt/sprites/animation.coffee +13 -0
- data/app/assets/javascripts/agt/sprites/sprite.coffee +30 -0
- data/app/assets/javascripts/agt/widgets/hash.coffee +36 -0
- data/app/assets/javascripts/agt/widgets/widgets.coffee +194 -0
- data/app/assets/javascripts/agt/widgets/widgets/checked_input.coffee +7 -0
- data/app/assets/javascripts/agt/widgets/widgets/focus_bubbling.coffee +15 -0
- data/lib/agt.rb +8 -0
- data/lib/agt/version.rb +5 -0
- 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
|