forked from hubotio/hubot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbrain.coffee
159 lines (135 loc) · 4.21 KB
/
brain.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
{EventEmitter} = require 'events'
User = require './user'
class Brain extends EventEmitter
# Represents somewhat persistent storage for the robot. Extend this.
#
# Returns a new Brain with no external storage.
constructor: (robot) ->
@data =
users: { }
_private: { }
@autoSave = true
robot.on "running", =>
@resetSaveInterval 5
# Public: Store key-value pair under the private namespace and extend
# existing @data before emitting the 'loaded' event.
#
# Returns the instance for chaining.
set: (key, value) ->
if key is Object(key)
pair = key
else
pair = {}
pair[key] = value
extend @data._private, pair
@emit 'loaded', @data
@
# Public: Get value by key from the private namespace in @data
# or return null if not found.
#
# Returns the value.
get: (key) ->
@data._private[key] ? null
# Public: Remove value by key from the private namespace in @data
# if it exists
#
# Returns the instance for chaining.
remove: (key) ->
delete @data._private[key] if @data._private[key]?
@
# Public: Emits the 'save' event so that 'brain' scripts can handle
# persisting.
#
# Returns nothing.
save: ->
@emit 'save', @data
# Public: Emits the 'close' event so that 'brain' scripts can handle closing.
#
# Returns nothing.
close: ->
clearInterval @saveInterval
@save()
@emit 'close'
# Public: Enable or disable the automatic saving
#
# enabled - A boolean whether to autosave or not
#
# Returns nothing
setAutoSave: (enabled) ->
@autoSave = enabled
# Public: Reset the interval between save function calls.
#
# seconds - An Integer of seconds between saves.
#
# Returns nothing.
resetSaveInterval: (seconds) ->
clearInterval @saveInterval if @saveInterval
@saveInterval = setInterval =>
@save() if @autoSave
, seconds * 1000
# Public: Merge keys loaded from a DB against the in memory representation.
#
# Returns nothing.
#
# Caveats: Deeply nested structures don't merge well.
mergeData: (data) ->
for k of (data or { })
@data[k] = data[k]
@emit 'loaded', @data
# Public: Get an Array of User objects stored in the brain.
#
# Returns an Array of User objects.
users: ->
@data.users
# Public: Get a User object given a unique identifier.
#
# Returns a User instance of the specified user.
userForId: (id, options) ->
user = @data.users[id]
unless user
user = new User id, options
@data.users[id] = user
if options and options.room and (!user.room or user.room isnt options.room)
user = new User id, options
@data.users[id] = user
user
# Public: Get a User object given a name.
#
# Returns a User instance for the user with the specified name.
userForName: (name) ->
result = null
lowerName = name.toLowerCase()
for k of (@data.users or { })
userName = @data.users[k]['name']
if userName? and userName.toLowerCase() is lowerName
result = @data.users[k]
result
# Public: Get all users whose names match fuzzyName. Currently, match
# means 'starts with', but this could be extended to match initials,
# nicknames, etc.
#
# Returns an Array of User instances matching the fuzzy name.
usersForRawFuzzyName: (fuzzyName) ->
lowerFuzzyName = fuzzyName.toLowerCase()
user for key, user of (@data.users or {}) when (
user.name.toLowerCase().lastIndexOf(lowerFuzzyName, 0) is 0
)
# Public: If fuzzyName is an exact match for a user, returns an array with
# just that user. Otherwise, returns an array of all users for which
# fuzzyName is a raw fuzzy match (see usersForRawFuzzyName).
#
# Returns an Array of User instances matching the fuzzy name.
usersForFuzzyName: (fuzzyName) ->
matchedUsers = @usersForRawFuzzyName(fuzzyName)
lowerFuzzyName = fuzzyName.toLowerCase()
for user in matchedUsers
return [user] if user.name.toLowerCase() is lowerFuzzyName
matchedUsers
# Private: Extend obj with objects passed as additional args.
#
# Returns the original object with updated changes.
extend = (obj, sources...) ->
for source in sources
obj[key] = value for own key, value of source
obj
module.exports = Brain