lita-markov 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 80906c8495bb1dcbbc33b970047390e606b429c8
4
+ data.tar.gz: 85f84a17b45289e6c86334318322eebba6724b8f
5
+ SHA512:
6
+ metadata.gz: f7c18adeba628b7e6cc48a22922fd745595104ce6846c919b773ab475e7c22b4d2e852d747055adadaec74b0dc881cab36254b305ab4c2df179c6a77e1b118e3
7
+ data.tar.gz: e4fce6fb0f3d70d04d2153fb202d1740c223abadc475a18a6629ba5080f211219dc58a0817bd36d58d6529801b8da7a2eaeb700585b7bb69d7ff1c20daf45145
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2015 Dirk Gadsden
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of Roost nor the names of its contributors may be used to
15
+ endorse or promote products derived from this software without specific
16
+ prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # Markov chains for Lita
2
+
3
+ Listens to your public chat rooms and generates Markov chain databases
4
+ for each user.
5
+
6
+ ## Installation
7
+
8
+ Add `lita-markov` to your Lita instance's Gemfile:
9
+
10
+ ``` ruby
11
+ gem 'lita-markov'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ The bot will automatically ingest all messages into the Redis-backed Markov
17
+ chain database. You can then query the bot for a generated chain:
18
+
19
+ ```
20
+ user> mybot markov dirk
21
+ mybot> I love cookies!
22
+ ```
23
+
24
+ ## License
25
+
26
+ Licensed under the 3-clause BSD license. See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,13 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require 'marky_markov/persistent_json_dictionary'
8
+ require 'lita/handlers/markov'
9
+
10
+ # Lita::Handlers::Markov.template_root File.expand_path(
11
+ # File.join("..", "..", "templates"),
12
+ # __FILE__
13
+ # )
@@ -0,0 +1,64 @@
1
+ module Lita::Handlers
2
+ class Markov < Lita::Handler
3
+ Dictionary = MarkyMarkov::PersistentJSONDictionary
4
+
5
+ REDIS_KEY_PREFIX = 'lita-markov:'
6
+
7
+ route(/.+/, :ingest, command: false)
8
+
9
+ route(/markov (.+)/, :generate, command: true, help: {
10
+ 'markov USER' => 'Generate a markov chain from the given user.'
11
+ })
12
+
13
+ def ingest(chat)
14
+ # Don't ingest messages addressed to ourselves
15
+ return if chat.command?
16
+
17
+ message = chat.matches[0].strip
18
+
19
+ # Get the mention name (ie. 'dirk') of the user
20
+ name = chat.user.mention_name
21
+ dictionary = dictionary_for_user name
22
+
23
+ # Passing `false` to indicate it's a string and not a file name
24
+ dictionary.parse_source message, false
25
+
26
+ save_dictionary name, dictionary
27
+ end
28
+
29
+ def generate(chat)
30
+ name = chat.matches[0][0].strip
31
+
32
+ dictionary = dictionary_for_user name
33
+ generator = MarkovSentenceGenerator.new dictionary
34
+
35
+ begin
36
+ sentence = generator.generate_sentence 1
37
+
38
+ chat.reply sentence
39
+ rescue EmptyDictionaryError
40
+ chat.reply "Looks like #{name} hasn't said anything!"
41
+ end
42
+ end
43
+
44
+ def save_dictionary(name, dictionary)
45
+ redis.set key_for_user(name), dictionary.to_json
46
+ end
47
+
48
+ def dictionary_for_user(name)
49
+ key = key_for_user name
50
+ dictionary = Dictionary.new name
51
+ json = redis.get key
52
+
53
+ dictionary.load_json(json) if json
54
+
55
+ dictionary
56
+ end
57
+
58
+ def key_for_user(name)
59
+ REDIS_KEY_PREFIX+name.downcase
60
+ end
61
+
62
+ Lita.register_handler self
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ require 'marky_markov'
2
+ require 'oj'
3
+
4
+ module MarkyMarkov
5
+ class PersistentJSONDictionary < ::PersistentDictionary
6
+ def initialize(*args)
7
+ super(*args)
8
+
9
+ @dictionary = {}
10
+ @capitalized_words = []
11
+ end
12
+
13
+ # No-op instead of reading from the filesystem
14
+ def open_dictionary
15
+ nil
16
+ end
17
+
18
+ def load_json(json)
19
+ data = Oj.load json
20
+
21
+ @depth = data['depth']
22
+ @dictionary = data['dictionary']
23
+ @capitalized_words = data['capitalized_words']
24
+ end
25
+
26
+ def to_json
27
+ Oj.dump(
28
+ 'depth' => @depth,
29
+ 'dictionary' => @dictionary,
30
+ 'capitalized_words' => @capitalized_words
31
+ )
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-markov"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["Dirk Gadsden"]
5
+ spec.email = ["dirk@dirk.to"]
6
+ spec.description = "Markov chains for Lita."
7
+ spec.summary = spec.description
8
+ spec.homepage = "http://github.com/dirk/lita-markov"
9
+ spec.metadata = { "lita_plugin_type" => "handler" }
10
+
11
+ spec.files = `git ls-files`.split($/)
12
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
13
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
+ spec.require_paths = ["lib"]
15
+
16
+ spec.add_runtime_dependency "lita", ">= 4.6"
17
+ spec.add_runtime_dependency "marky_markov", "~> 0.3.5"
18
+ spec.add_runtime_dependency "oj", "~> 2.13.1"
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "pry-byebug"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rack-test"
24
+ spec.add_development_dependency "rspec", ">= 3.0.0"
25
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ whoami:
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'pry'
3
+
4
+ describe Lita::Handlers::Markov, lita_handler: true do
5
+ before(:each) do
6
+ Lita.redis.flushall
7
+ end
8
+
9
+ it "won't call #ingest for non-command messages" do
10
+ expect(subject).to_not receive(:ingest)
11
+
12
+ send_message "#{robot.name} foo"
13
+ send_command 'bar'
14
+ end
15
+
16
+ it "will ingest a message into that person's dictionary" do
17
+ send_message 'hello markov world'
18
+ send_message 'hello markov planet'
19
+
20
+ dictionary = subject.dictionary_for_user user.mention_name
21
+
22
+ # Check that the messages made it into the dictionary
23
+ expect(dictionary.dictionary[['hello', 'markov']]).to eql ['world', 'planet']
24
+ end
25
+
26
+ it 'will build a sentence' do
27
+ send_message 'I love cookies!'
28
+ send_message 'I love pancakes!'
29
+
30
+ send_command "#{robot.name} markov #{user.mention_name}"
31
+
32
+ expect(replies.count).to eql 1
33
+
34
+ possible_replies = [
35
+ 'I love cookies!',
36
+ 'I love pancakes!'
37
+ ]
38
+ expect(possible_replies).to include replies[0]
39
+ end
40
+
41
+ it "will complain if the user hasn't said anything" do
42
+ send_command "#{robot.name} markov #{user.mention_name}"
43
+
44
+ expect(replies.count).to eql 1
45
+ expect(replies[0]).to eql "Looks like Test User hasn't said anything!"
46
+ end
47
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe MarkyMarkov::PersistentJSONDictionary do
4
+ subject { MarkyMarkov::PersistentJSONDictionary.new 'whoa' }
5
+
6
+ it 'initializes with sensible defaults' do
7
+ expect(subject.dictionary).to eq({})
8
+ end
9
+
10
+ it 'saves a dictionary' do
11
+ subject.add_word ['a', 'b'], 'c'
12
+
13
+ json = subject.to_json
14
+
15
+ expect(json).to eql '{"depth":2,"dictionary":{"^#1":[["a","b"],["c"]]},"capitalized_words":[]}'
16
+ end
17
+
18
+ it 'saves and loads a dictionary' do
19
+ subject.add_word ['a', 'b'], 'c'
20
+
21
+ json = subject.to_json
22
+
23
+ new_dictionary = MarkyMarkov::PersistentJSONDictionary.new 'whoa-another-one'
24
+ new_dictionary.load_json json
25
+
26
+ expect(new_dictionary.dictionary).to eql(['a', 'b'] => ['c'])
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ require 'lita-markov'
2
+ require 'lita/rspec'
3
+
4
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
+ # was generated with Lita 4, the compatibility mode should be left disabled.
6
+ Lita.version_3_compatibility_mode = false
File without changes
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-markov
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dirk Gadsden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: marky_markov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: oj
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.13.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.13.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.0
125
+ description: Markov chains for Lita.
126
+ email:
127
+ - dirk@dirk.to
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - Gemfile
134
+ - LICENSE
135
+ - README.md
136
+ - Rakefile
137
+ - lib/lita-markov.rb
138
+ - lib/lita/handlers/markov.rb
139
+ - lib/marky_markov/persistent_json_dictionary.rb
140
+ - lita-markov.gemspec
141
+ - locales/en.yml
142
+ - spec/lita/handlers/markov_spec.rb
143
+ - spec/marky_markov/persistent_json_dictionary_spec.rb
144
+ - spec/spec_helper.rb
145
+ - templates/.gitkeep
146
+ homepage: http://github.com/dirk/lita-markov
147
+ licenses: []
148
+ metadata:
149
+ lita_plugin_type: handler
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 2.4.5.1
167
+ signing_key:
168
+ specification_version: 4
169
+ summary: Markov chains for Lita.
170
+ test_files:
171
+ - spec/lita/handlers/markov_spec.rb
172
+ - spec/marky_markov/persistent_json_dictionary_spec.rb
173
+ - spec/spec_helper.rb