mobb 0.1.0

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
+ SHA256:
3
+ metadata.gz: 75d6f6e3f306dcd58cd2bcf5f715d860448c90db93f792e500dbd7b8805ae24b
4
+ data.tar.gz: 5ab8a6f5af4bfb8e9ea8ea7176c61f7cadcc0b6ceb43766fc0ae78b53f31db0b
5
+ SHA512:
6
+ metadata.gz: 4881e20aee0c8f698b7e1486f26b7902eff6d945d3ee84d8909ed6e9e532e236093f85abc62dea09807087d2aeaaab70eb22fbfa24d872d016d87fe2bace3475
7
+ data.tar.gz: '09e34fa992c82bb08f10468fbd8fdd3fab272344c1bf899384727e10a95504dd77be77d19267d8f3d973e576a2f1b2c6641b8df0561f72ffb68ebf937e91a78a'
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 kinoppyd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Mobb
2
+
3
+ Mobb is the simplest, most lightweight, fastest Bot framework written by Ruby.
4
+
5
+ # Install
6
+
7
+ you can install Mobb by rubygems like
8
+
9
+ ```
10
+ gem isntall mobb
11
+ ```
12
+
13
+ or you can use a bundler. Writes the following in Gemfile
14
+
15
+ ```
16
+ source "https://rubygems.org"
17
+
18
+ gem "mobb", "~> 0.1"
19
+ ```
20
+
21
+ and install
22
+
23
+ ```
24
+ bundle install
25
+ ```
26
+
27
+ # Examples
28
+
29
+ Write your logic in `app.rb` like...
30
+
31
+ ```ruby
32
+ require 'mobb'
33
+
34
+ set :name, "example bot"
35
+ '
36
+ on "hello" do
37
+ "hi! i'm #{settings.name}!"
38
+ end
39
+ ```
40
+
41
+ and start mobb application
42
+
43
+ ```
44
+ ruby app.rb
45
+ ```
46
+
47
+ then the shell will start to wait for your input, so you can type 'hello' and hit enter, then you get.
48
+
49
+ ```
50
+ hi! i'm example bot!"
51
+ ```
52
+
53
+ # Service handlers
54
+
55
+ Mobb is implemented based on [Repp](https://github.com/kinoppyd/repp) Interface.
56
+ Shell and Slack adapter is currently available.
57
+
58
+ ```ruby
59
+ require 'mobb'
60
+ set :serice, 'slack'
61
+
62
+ on /hey (\w+)/ do |someone|
63
+ "hey #{someone}, waz up?"
64
+ end
65
+ ```
66
+
67
+ # TODO
68
+
69
+ + Test, Test, Test
70
+ + Documents
71
+ + Parallel event handling
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,23 @@
1
+ require 'mobb'
2
+
3
+ set :service, 'slack'
4
+ set :name, "example bot"
5
+
6
+ on "hello" do
7
+ "Hi! I'm #{settings.name}"
8
+ end
9
+
10
+ # Warning this is bad implementation
11
+ # inifinity loop happend
12
+ receive "Yo", laziness: true do
13
+ "Yo"
14
+ end
15
+
16
+ receive /hey (\w+)/ do |someone|
17
+ "hey #{someone}, waz up?"
18
+ end
19
+
20
+ # This function is not implements yet
21
+ #every 1.day, at: '15:30', exclude: :holiday do
22
+ # 'Stund up daily meeting time!'
23
+ #end
data/lib/mobb.rb ADDED
@@ -0,0 +1 @@
1
+ require "mobb/main"
data/lib/mobb/base.rb ADDED
@@ -0,0 +1,354 @@
1
+ require 'repp'
2
+ require "mobb/version"
3
+
4
+ module Mobb
5
+ class Matcher
6
+ def initialize(pattern, options) @pattern, @options = pattern, options; end
7
+ def regexp?; pattern.is_a?(Regexp); end
8
+ def inspect; "pattern: #{@pattern}, options #{@options}"; end
9
+ def invoke(time = Time.now) @options[:last_invoked] = time; end
10
+
11
+ def match?(context)
12
+ case context
13
+ when String
14
+ string_matcher(context)
15
+ when Time
16
+ # TODO: do something
17
+ false
18
+ when Array
19
+ context.all? { |c| match?(c) }
20
+ else
21
+ false
22
+ end
23
+ end
24
+
25
+ class Matched
26
+ attr_reader :pattern, :matched
27
+ def initialize(pattern, matched) @pattern, @matched = pattern, matched; end
28
+ end
29
+
30
+ def pattern; @pattern; end
31
+
32
+ def string_matcher(string)
33
+ case pattern
34
+ when Regexp
35
+ if res = pattern.match(string)
36
+ Matched.new(pattern, res.captures)
37
+ else
38
+ false
39
+ end
40
+ when String
41
+ @options[:laziness] ? string.include?(pattern) : string == pattern
42
+ else
43
+ false
44
+ end
45
+ end
46
+ end
47
+
48
+ class Base
49
+ def call(env)
50
+ dup.call!(env)
51
+ end
52
+
53
+ def tick(env)
54
+ dup.tick!(env)
55
+ end
56
+
57
+ def call!(env)
58
+ @env = env
59
+ invoke { dispatch! }
60
+ [@body, @attachments]
61
+ end
62
+
63
+ def tick!(env)
64
+ fail # TODO: write logic here
65
+ end
66
+
67
+ def dispatch!
68
+ # TODO: encode input messages
69
+
70
+ invoke do
71
+ # TODO: before filters
72
+ handle_event
73
+ end
74
+ ensure
75
+ # TODO: after fillters
76
+ end
77
+
78
+ def invoke
79
+ res = catch(:halt) { yield }
80
+ return if res.nil?
81
+
82
+ res = [res] if String === res
83
+ if Array === res && String === res.first
84
+ tmp = res.dup
85
+ @body = tmp.shift
86
+ @attachments = tmp.pop
87
+ else
88
+ @attachments = res
89
+ end
90
+ nil
91
+ end
92
+
93
+ def handle_event(base = settings, passed_block = nil)
94
+ if responds = base.events[@env.event_type]
95
+ responds.each do |pattern, block|
96
+ process_event(pattern) do |*args|
97
+ event_eval { block[*args] }
98
+ end
99
+ end
100
+ end
101
+
102
+ # TODO: Define respond missing if receive reply message
103
+ nil
104
+ end
105
+
106
+ def process_event(pattern, block = nil, values = [])
107
+ res = pattern.match?(@env.body)
108
+ case res
109
+ when ::Mobb::Matcher::Matched
110
+ yield(self, *(res.matched))
111
+ when TrueClass
112
+ yield self
113
+ else
114
+ nil
115
+ end
116
+ end
117
+
118
+ def event_eval; throw :halt, yield; end
119
+
120
+ def settings
121
+ self.class.settings
122
+ end
123
+
124
+ class << self
125
+ CALLERS_TO_IGNORE = [
126
+ /\/mobb(\/(base|main|show_exceptions))?\.rb$/, # all sinatra code
127
+ /^\(.*\)$/, # generated code
128
+ /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
129
+ /active_support/, # active_support require hacks
130
+ /bundler(\/runtime)?\.rb/, # bundler require hacks
131
+ /<internal:/, # internal in ruby >= 1.9.2
132
+ /src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
133
+ ]
134
+
135
+ attr_reader :events
136
+
137
+ def reset!
138
+ @events = {}
139
+ end
140
+
141
+ def settings
142
+ self
143
+ end
144
+
145
+ def receive(pattern, options = {}, &block) event(:message, pattern, options, &block); end
146
+ alias :on :receive
147
+
148
+ #def every(pattern, options = {}, &block) event(:cron, pattern, options, &block); end
149
+
150
+ def event(type, pattern, options, &block)
151
+ (@events[type] ||= []) << compile!(type, pattern, options, &block)
152
+ end
153
+
154
+ def compile!(type, pattern, option, &block)
155
+ matcher = compile(pattern, option)
156
+ unbound_method = generate_method("#{type}", &block)
157
+ wrapper = block.arity != 0 ?
158
+ proc { |instance, args| unbound_method.bind(instance).call(*args) } :
159
+ proc { |instance, args| unbound_method.bind(instance).call }
160
+ [matcher, wrapper]
161
+ end
162
+
163
+ def compile(pattern, options) Matcher.new(pattern, options); end
164
+
165
+ def generate_method(name, &block)
166
+ define_method(name, &block)
167
+ method = instance_method(name)
168
+ remove_method(name)
169
+ method
170
+ end
171
+
172
+ def development?; environment == :development; end
173
+ def production?; environment == :production; end
174
+ def test?; environment == :test; end
175
+
176
+ def set(option, value = (not_set = true), ignore_setter = false, &block)
177
+ raise ArgumentError if block && !not_set
178
+ value, not_set = block, false if block
179
+
180
+ if not_set
181
+ raise ArgumentError unless option.respond_to?(:each)
182
+ option.each { |k,v| set(k,v) }
183
+ return self
184
+ end
185
+
186
+ setter_name = "#{option}="
187
+ if respond_to?(setter_name) && ! ignore_setter
188
+ return __send__(setter_name, value)
189
+ end
190
+
191
+ setter = proc { |val| set(option, val, true) }
192
+ getter = proc { value }
193
+
194
+ case value
195
+ when Proc
196
+ getter = value
197
+ when Symbol, Integer, FalseClass, TrueClass, NilClass
198
+ getter = value.inspect
199
+ when Hash
200
+ setter = proc do |val|
201
+ val = value.merge(val) if Hash === val
202
+ set(option, val, true)
203
+ end
204
+ end
205
+
206
+ define_singleton(setter_name, setter)
207
+ define_singleton(option, getter)
208
+ define_singleton("#{option}?", "!!#{option}") unless method_defined?("#{option}?")
209
+ self
210
+ end
211
+
212
+ def enable(*options) options.each { |option| set(option, true) }; end
213
+ def disable(*options) options.each { |option| set(option, false) }; end
214
+ def clear(*options) options.each { |option| set(option, nil) }; end
215
+
216
+ def run!(options = {}, &block)
217
+ return if running?
218
+
219
+ set options
220
+ handler = detect_repp_handler
221
+ handler_name = handler.name.gsub(/.*::/, '')
222
+ service_settings = settings.respond_to?(:service_settings) ? settings.service_settings : {}
223
+
224
+ begin
225
+ start_service(handler, service_settings, handler_name, &block)
226
+ rescue => e
227
+ $stderr.puts e.message
228
+ $stderr.puts e.backtrace
229
+ ensure
230
+ quit!
231
+ end
232
+ end
233
+
234
+ def quit!
235
+ return unless running?
236
+ running_service.respond_to?(:stop!) ? running_service.stop! : running_service.stop
237
+ $stderr.puts "== Great sound Mobb, thank you so much"
238
+ clear :running_service, :handler_name
239
+ end
240
+
241
+ def running?
242
+ running_service?
243
+ end
244
+
245
+ private
246
+
247
+ def start_service(handler, service_settings, handler_name)
248
+ handler.run(self, service_settings) do |service|
249
+ $stderr.puts "== Mobb (v#{Mobb::VERSION}) is in da house with #{handler_name}. Make some noise!"
250
+
251
+ setup_traps
252
+ set running_service: service
253
+ set handler_name: handler_name
254
+
255
+ yield service if block_given?
256
+ end
257
+ end
258
+
259
+ def setup_traps
260
+ if traps?
261
+ at_exit { quit! }
262
+
263
+ [:INT, :TERM].each do |signal|
264
+ old_handler = Signal.trap(signal) do
265
+ quit!
266
+ old_handler.respond_to?(:call) ? old_handler.call : exit
267
+ end
268
+ end
269
+
270
+ disable :traps
271
+ end
272
+ end
273
+
274
+ def detect_repp_handler
275
+ services = Array(service)
276
+ services.each do |service_name|
277
+ begin
278
+ return Repp::Handler.get(service_name.to_s)
279
+ rescue LoadError, NameError
280
+ end
281
+ end
282
+ fail "Service handler (#{services.join(',')}) not found"
283
+ end
284
+
285
+ def define_singleton(name, content = Proc.new)
286
+ singleton_class.class_eval do
287
+ undef_method(name) if method_defined?(name)
288
+ String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content)
289
+ end
290
+ end
291
+
292
+ def caller_files
293
+ cleaned_caller(1).flatten
294
+ end
295
+
296
+ def cleaned_caller(keep = 3)
297
+ caller(1).
298
+ map! { |line| line.split(/:(?=\d|in )/, 3)[0,keep] }.
299
+ reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
300
+ end
301
+
302
+ def inherited(subclass)
303
+ subclass.reset!
304
+ subclass.set :app_file, caller_files.first unless subclass.app_file?
305
+ super
306
+ end
307
+ end
308
+
309
+ reset!
310
+
311
+ set :name, 'mobb'
312
+ set :environment, (ENV['APP_ENV'] || ENV['REPP_ENV'] || :development).to_sym
313
+
314
+ disable :run, :quiet
315
+ clear :running_service, :handler_name
316
+ enable :traps
317
+ set :service, %w[shell]
318
+
319
+ clear :app_file
320
+ end
321
+
322
+ class Application < Base
323
+ set :logging, Proc.new { !test? }
324
+ set :run, Proc.new { !test? }
325
+ clear :app_file
326
+
327
+ def self.register(*extensions, &block)
328
+ added_methods = extensions.flat_map(&:public_instance_methods)
329
+ Delegator.delegate(*added_methods)
330
+ super(*extensions, &block)
331
+ end
332
+ end
333
+
334
+ module Delegator #:nodoc:
335
+ def self.delegate(*methods)
336
+ methods.each do |method_name|
337
+ define_method(method_name) do |*args, &block|
338
+ return super(*args, &block) if respond_to? method_name
339
+ Delegator.target.send(method_name, *args, &block)
340
+ end
341
+ private method_name
342
+ end
343
+ end
344
+
345
+ delegate :receive, :on, #:every,
346
+ :set, :enable, :disable, :clear
347
+
348
+ class << self
349
+ attr_accessor :target
350
+ end
351
+
352
+ self.target = Application
353
+ end
354
+ end
data/lib/mobb/main.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'mobb/base'
2
+
3
+ module Mobb
4
+ class Application < Base
5
+ set app_file: caller_files.first || $0
6
+
7
+ set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
8
+ end
9
+
10
+ at_exit { Application.run! if $!.nil? && Application.run? }
11
+ end
12
+
13
+ extend Mobb::Delegator
14
+
15
+ #class Repp::Builder
16
+ # include Mobb::Delegator
17
+ #end
@@ -0,0 +1,3 @@
1
+ module Mobb
2
+ VERSION = "0.1.0"
3
+ end
data/mobb.gemspec ADDED
@@ -0,0 +1,27 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "mobb/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mobb"
8
+ spec.version = Mobb::VERSION
9
+ spec.authors = ["kinoppyd"]
10
+ spec.email = ["WhoIsDissolvedGirl+github@gmail.com"]
11
+
12
+ spec.summary = %q{Mobb is a lightweight Bot framework like Sinatra}
13
+ spec.description = %q{Mobb provides bot DSL}
14
+ spec.homepage = "https://github.com/kinoppyd/mobb"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.require_paths = ["lib"]
21
+
22
+ #spec.add_dependency "repp", "~> 0.1"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "~> 5.0"
27
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mobb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - kinoppyd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-06-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ description: Mobb provides bot DSL
56
+ email:
57
+ - WhoIsDissolvedGirl+github@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - examples/slack_bot.rb
68
+ - lib/mobb.rb
69
+ - lib/mobb/base.rb
70
+ - lib/mobb/main.rb
71
+ - lib/mobb/version.rb
72
+ - mobb.gemspec
73
+ homepage: https://github.com/kinoppyd/mobb
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.7.6
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Mobb is a lightweight Bot framework like Sinatra
97
+ test_files: []