juvet 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.md +7 -0
- data/README.md +69 -0
- data/Rakefile +10 -0
- data/juvet.gemspec +24 -0
- data/lib/juvet/adapters/null_adapter.rb +26 -0
- data/lib/juvet/adapters/redis_adapter.rb +53 -0
- data/lib/juvet/attributable.rb +57 -0
- data/lib/juvet/bot.rb +36 -0
- data/lib/juvet/bot_repository.rb +7 -0
- data/lib/juvet/configuration/adapter.rb +35 -0
- data/lib/juvet/configuration/mapping.rb +15 -0
- data/lib/juvet/configuration.rb +20 -0
- data/lib/juvet/entity_not_found_error.rb +4 -0
- data/lib/juvet/mapper/collection.rb +28 -0
- data/lib/juvet/mapper.rb +21 -0
- data/lib/juvet/repository.rb +43 -0
- data/lib/juvet/string.rb +20 -0
- data/lib/juvet/version.rb +3 -0
- data/lib/juvet.rb +19 -0
- data/spec/juvet/adapters/null_adapter_spec.rb +28 -0
- data/spec/juvet/adapters/redis_adapter_spec.rb +92 -0
- data/spec/juvet/attributable_spec.rb +85 -0
- data/spec/juvet/bot_spec.rb +61 -0
- data/spec/juvet/configuration/adapter_spec.rb +39 -0
- data/spec/juvet/configuration/mapping_spec.rb +18 -0
- data/spec/juvet/configuration_spec.rb +31 -0
- data/spec/juvet/mapper/collection_spec.rb +19 -0
- data/spec/juvet/mapper_spec.rb +47 -0
- data/spec/juvet/repository_spec.rb +49 -0
- data/spec/juvet/string_spec.rb +13 -0
- data/spec/juvet_spec.rb +20 -0
- data/spec/spec_helper.rb +14 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 51a223cb59aebbef58cff5014a5e4982c468eed8
|
4
|
+
data.tar.gz: 2c835354dc21deaebbe4a1526cfd75cccd15f319
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddbf2a6c64b316fc365fab22a66d47370c9683957719ad9b5323c132eb253691b8db0c42f180ec59791268b9c3031de8d51d44b35da4c4a48558e4fbd647aef8
|
7
|
+
data.tar.gz: d5d736c01b01777b7da50de546c0c088f7ddb3a804e46389034f385900dcd8014275defb26e26567a47f81969a770e4bd93ccf74d02a11625f76f320864f212c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
juvet (0.0.1)
|
5
|
+
redis
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
rake (10.5.0)
|
12
|
+
redis (3.2.2)
|
13
|
+
rspec (3.4.0)
|
14
|
+
rspec-core (~> 3.4.0)
|
15
|
+
rspec-expectations (~> 3.4.0)
|
16
|
+
rspec-mocks (~> 3.4.0)
|
17
|
+
rspec-core (3.4.2)
|
18
|
+
rspec-support (~> 3.4.0)
|
19
|
+
rspec-expectations (3.4.0)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.4.0)
|
22
|
+
rspec-mocks (3.4.1)
|
23
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
+
rspec-support (~> 3.4.0)
|
25
|
+
rspec-support (3.4.1)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
juvet!
|
32
|
+
rake
|
33
|
+
rspec
|
34
|
+
|
35
|
+
BUNDLED WITH
|
36
|
+
1.11.2
|
data/LICENSE.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2016 Tatsu, LLC.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
juvet
|
2
|
+
=====
|
3
|
+
|
4
|
+
## DESCRIPTION
|
5
|
+
|
6
|
+
A factory and storage mechanism to store your bot information, backed by Redis.
|
7
|
+
|
8
|
+
A word about the future
|
9
|
+
-----------------------
|
10
|
+
|
11
|
+
The initial intent of this gem is to just store information about the bots you are running. This will in the near future be able to start, stop, and pause bots by turning on/off their senses. In addition by integrating message queuing (right now just by using Redis) will be able to send messages to/from the bots within the factory. This will allow things such as adding health checks, broadcasting messages to all bots, etc.
|
12
|
+
|
13
|
+
## USAGE
|
14
|
+
|
15
|
+
In order to configure Juvet, you will want to specify the repository it will be using. An initializer of some sort would be ideal to place this code in.
|
16
|
+
|
17
|
+
```
|
18
|
+
Juvet.configure do
|
19
|
+
adapter :redis, url: ENV["REDIS_URL"]
|
20
|
+
mapping do
|
21
|
+
collection :bots do
|
22
|
+
repository Juvet::BotRepository
|
23
|
+
entity Juvet::Bot
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
* Creating a bot
|
30
|
+
|
31
|
+
```
|
32
|
+
Juvet::Bot.create! bot_access_token, team_id: "T12345", status: :active
|
33
|
+
```
|
34
|
+
|
35
|
+
* Updating a bot
|
36
|
+
|
37
|
+
```
|
38
|
+
bot = Juvet::Bot.find bot_access_token
|
39
|
+
bot.status = :inactive
|
40
|
+
bot.update!
|
41
|
+
```
|
42
|
+
|
43
|
+
* Destroying a bot
|
44
|
+
|
45
|
+
```
|
46
|
+
Juvet::Bot.destroy! bot_access_token
|
47
|
+
```
|
48
|
+
|
49
|
+
## CONTRIBUTING
|
50
|
+
|
51
|
+
1. Clone the repository `git clone https://github.com/tatsuio/juvet`
|
52
|
+
1. Create a feature branch `git checkout -b my-awesome-feature`
|
53
|
+
1. Codez!
|
54
|
+
1. Commit your changes (small commits please)
|
55
|
+
1. Push your new branch `git push origin my-awesome-feature`
|
56
|
+
1. Create a pull request `hub pull-request -b tatsuio:master -h tatsuio:my-awesome-feature`
|
57
|
+
|
58
|
+
## RELEASING A NEW GEM
|
59
|
+
|
60
|
+
1. Bump the VERSION in `lib/juvet/version.rb`
|
61
|
+
1. run `bundle exec rake build`
|
62
|
+
1. Commit changes and push to GitHub
|
63
|
+
1. run `bundle exec rake release`
|
64
|
+
|
65
|
+
## LICENSE
|
66
|
+
|
67
|
+
Copyright (c) 2016, [Tatsu, LLC](http://tatsu.io).
|
68
|
+
|
69
|
+
This project is licensed under the [MIT License](LICENSE.md).
|
data/Rakefile
ADDED
data/juvet.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "juvet/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "juvet"
|
8
|
+
spec.version = Juvet::VERSION
|
9
|
+
spec.authors = ["Jamie Wright"]
|
10
|
+
spec.email = ["jamie@tatsu.io"]
|
11
|
+
spec.summary = "The factory for bots."
|
12
|
+
spec.description = "A factory and storage mechanism to store your bot information, backed by Redis."
|
13
|
+
spec.homepage = "http://github.com/tatsuio/juvet"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = ">= 2.2"
|
22
|
+
|
23
|
+
spec.add_runtime_dependency("redis")
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Juvet
|
2
|
+
module Adapters
|
3
|
+
class NullAdapter
|
4
|
+
def initialize(collection=nil, options={})
|
5
|
+
end
|
6
|
+
|
7
|
+
def create(entity)
|
8
|
+
entity
|
9
|
+
end
|
10
|
+
|
11
|
+
def destroy(id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def persist(entity)
|
18
|
+
entity
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(entity)
|
22
|
+
entity
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "json"
|
2
|
+
require "redis"
|
3
|
+
|
4
|
+
module Juvet
|
5
|
+
module Adapters
|
6
|
+
class RedisAdapter
|
7
|
+
attr_reader :collection, :redis
|
8
|
+
|
9
|
+
def initialize(collection, options={})
|
10
|
+
@collection = collection
|
11
|
+
@redis = Redis.new options
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(entity)
|
15
|
+
update_attributes entity
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy(id)
|
19
|
+
redis.del collection_key(id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def find(id)
|
23
|
+
attributes = redis.get(collection_key(id))
|
24
|
+
return nil if attributes.nil?
|
25
|
+
collection.entity.new ({ id: id }).merge(JSON.load(attributes))
|
26
|
+
end
|
27
|
+
|
28
|
+
def persist(entity)
|
29
|
+
find(entity.id).nil? ? create(entity) : update_attributes(entity)
|
30
|
+
end
|
31
|
+
|
32
|
+
def update(entity)
|
33
|
+
raise EntityNotFoundError if find(entity.id).nil?
|
34
|
+
update_attributes entity
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def collection_key(id)
|
40
|
+
"#{Juvet::String.new(collection.name).underscore}:#{id}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def key(entity)
|
44
|
+
collection_key entity.id
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_attributes(entity)
|
48
|
+
redis.set key(entity), entity.attributes.to_json
|
49
|
+
entity
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Juvet
|
2
|
+
module Attributable
|
3
|
+
def initialize(attributes={})
|
4
|
+
initialize! attributes
|
5
|
+
attribute! attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize!(attributes)
|
9
|
+
attributes.each { |name, value| set_variable! name, value }
|
10
|
+
end
|
11
|
+
|
12
|
+
def attribute!(attributes)
|
13
|
+
(@_attributes ||= []).concat attributes.keys
|
14
|
+
attributes.keys.each { |name| define_attribute! name }
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes
|
18
|
+
attributes = {}
|
19
|
+
@_attributes.each do |attribute|
|
20
|
+
if self.respond_to? attribute
|
21
|
+
attributes[attribute] = self.send(attribute)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
attributes
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def create_method(name, &block)
|
30
|
+
self.class.send(:define_method, name, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_attribute!(name)
|
34
|
+
define_getter!(name)
|
35
|
+
define_setter!(name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def define_getter!(name)
|
39
|
+
create_method name do
|
40
|
+
instance_variable_get("@#{name}")
|
41
|
+
end unless respond_to? name
|
42
|
+
end
|
43
|
+
|
44
|
+
def define_setter!(name)
|
45
|
+
method = "#{name}="
|
46
|
+
create_method method do |value|
|
47
|
+
instance_variable_set("@#{name}", value)
|
48
|
+
end unless respond_to? method
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_variable!(name, value)
|
52
|
+
variable = "@#{name}"
|
53
|
+
instance_variable_set("@#{name}", value) \
|
54
|
+
unless instance_variable_defined? variable
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/juvet/bot.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Juvet
|
2
|
+
class Bot
|
3
|
+
include Attributable
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def create(id, attributes={})
|
9
|
+
new id, attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def create!(id, attributes={})
|
13
|
+
BotRepository.create create(id, attributes)
|
14
|
+
end
|
15
|
+
|
16
|
+
def destroy!(id)
|
17
|
+
BotRepository.destroy id
|
18
|
+
end
|
19
|
+
|
20
|
+
def find!(id)
|
21
|
+
BotRepository.find id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update!(attributes={})
|
26
|
+
BotRepository.update self
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def initialize(id, attributes={})
|
32
|
+
@id = id
|
33
|
+
super attributes
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Juvet
|
2
|
+
class Configuration
|
3
|
+
class Adapter
|
4
|
+
attr_reader :class_name
|
5
|
+
attr_reader :options
|
6
|
+
attr_reader :type
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
opts = (options || {}).dup
|
10
|
+
|
11
|
+
@type = opts.delete :type
|
12
|
+
@options = opts
|
13
|
+
@class_name = Juvet::String.new("#{type}_adapter").classify
|
14
|
+
end
|
15
|
+
|
16
|
+
def build(mapper)
|
17
|
+
load_adapter
|
18
|
+
instantiate_adapter mapper
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def load_adapter
|
24
|
+
require "juvet/adapters/#{type}_adapter"
|
25
|
+
rescue LoadError => e
|
26
|
+
raise LoadError.new("Cannot find Juvet adapter '#{type}' (#{e.message})")
|
27
|
+
end
|
28
|
+
|
29
|
+
def instantiate_adapter(mapper)
|
30
|
+
klass = Juvet::Adapters.const_get(class_name)
|
31
|
+
klass.new(mapper.collection_for_repository(klass), options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "configuration/adapter"
|
2
|
+
require_relative "configuration/mapping"
|
3
|
+
|
4
|
+
module Juvet
|
5
|
+
class Configuration
|
6
|
+
attr_reader :adapter
|
7
|
+
|
8
|
+
def adapter=(options)
|
9
|
+
@adapter ||= Juvet::Configuration::Adapter.new(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def mapping(&block)
|
13
|
+
@mapping ||= Juvet::Configuration::Mapping.new(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load!
|
17
|
+
adapter.build mapping.build
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Juvet
|
2
|
+
class Mapper
|
3
|
+
class Collection
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(name, &block)
|
7
|
+
@name = name
|
8
|
+
instance_eval(&block) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def entity(klass=nil)
|
12
|
+
if klass
|
13
|
+
@entity = klass
|
14
|
+
else
|
15
|
+
@entity
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def repository(klass=nil)
|
20
|
+
if klass
|
21
|
+
@repository = klass
|
22
|
+
else
|
23
|
+
@repository
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/juvet/mapper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "mapper/collection"
|
2
|
+
|
3
|
+
module Juvet
|
4
|
+
class Mapper
|
5
|
+
attr_reader :collections
|
6
|
+
|
7
|
+
def initialize(&block)
|
8
|
+
@collections = {}
|
9
|
+
|
10
|
+
instance_eval(&block) if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def collection(name, &block)
|
14
|
+
collections[name] = Juvet::Mapper::Collection.new name, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def collection_for_repository(klass)
|
18
|
+
collections.values.find { |collection| collection.repository == klass }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative "adapters/null_adapter"
|
2
|
+
|
3
|
+
module Juvet
|
4
|
+
module Repository
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
|
9
|
+
self.adapter = Adapters::NullAdapter.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def adapter
|
15
|
+
@adapter
|
16
|
+
end
|
17
|
+
|
18
|
+
def adapter=(adapter)
|
19
|
+
@adapter = adapter
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(entity)
|
23
|
+
adapter.create entity
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy(id)
|
27
|
+
adapter.destroy id
|
28
|
+
end
|
29
|
+
|
30
|
+
def find(id)
|
31
|
+
adapter.find id
|
32
|
+
end
|
33
|
+
|
34
|
+
def persist(entity)
|
35
|
+
adapter.persist entity
|
36
|
+
end
|
37
|
+
|
38
|
+
def update(entity)
|
39
|
+
adapter.update entity
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/juvet/string.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Juvet
|
2
|
+
class String
|
3
|
+
def initialize(string)
|
4
|
+
@string = string.to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def classify
|
8
|
+
string.split("_").map{ |w| w.capitalize }.join
|
9
|
+
end
|
10
|
+
|
11
|
+
def underscore
|
12
|
+
modified = string.gsub(/(.)([A-Z])/,'\1_\2')
|
13
|
+
modified.downcase
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :string
|
19
|
+
end
|
20
|
+
end
|
data/lib/juvet.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "juvet/attributable"
|
2
|
+
require_relative "juvet/bot"
|
3
|
+
require_relative "juvet/bot_repository"
|
4
|
+
require_relative "juvet/configuration"
|
5
|
+
require_relative "juvet/entity_not_found_error"
|
6
|
+
require_relative "juvet/mapper"
|
7
|
+
require_relative "juvet/repository"
|
8
|
+
require_relative "juvet/string"
|
9
|
+
|
10
|
+
module Juvet
|
11
|
+
def self.configuration
|
12
|
+
@configuration ||= Juvet::Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure
|
16
|
+
yield configuration if block_given?
|
17
|
+
configuration.load!
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
describe Juvet::Adapters::NullAdapter do
|
2
|
+
let(:entity) { Object.new }
|
3
|
+
subject { described_class.new }
|
4
|
+
|
5
|
+
describe "#create" do
|
6
|
+
it "simply returns the entity" do
|
7
|
+
expect(subject.create(entity)).to eq entity
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#find" do
|
12
|
+
it "returns nil" do
|
13
|
+
expect(subject.find("blah")).to be_nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#persist" do
|
18
|
+
it "simply returns the entity" do
|
19
|
+
expect(subject.persist(entity)).to eq entity
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#update" do
|
24
|
+
it "simply returns the entity" do
|
25
|
+
expect(subject.update(entity)).to eq entity
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "json"
|
2
|
+
require "./lib/juvet/adapters/redis_adapter"
|
3
|
+
|
4
|
+
describe Juvet::Adapters::RedisAdapter do
|
5
|
+
class Entity
|
6
|
+
include Juvet::Attributable
|
7
|
+
|
8
|
+
attr_accessor :id
|
9
|
+
attr_accessor :blah
|
10
|
+
|
11
|
+
def attributes
|
12
|
+
{ blah: blah }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:collection) { double(:collection, name: :entities, entity: Entity) }
|
17
|
+
let(:entity) { Entity.new id: 123 }
|
18
|
+
let(:url) { "redis://localhost:6379" }
|
19
|
+
subject { described_class.new collection, url: url, db: 15 }
|
20
|
+
|
21
|
+
before(:all) { @redis = Redis.new db: 15 }
|
22
|
+
after(:all) { @redis.flushdb }
|
23
|
+
|
24
|
+
describe "#create" do
|
25
|
+
it "stores the entity in the redis store" do
|
26
|
+
result = subject.create entity
|
27
|
+
|
28
|
+
expect(result).to eq entity
|
29
|
+
expect(@redis.get("entities:123")).to eq(JSON.generate({ blah: nil }))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#destroy" do
|
34
|
+
it "removes the entity from the redis store" do
|
35
|
+
id = subject.create(entity).id
|
36
|
+
subject.destroy id
|
37
|
+
|
38
|
+
expect(@redis.get("entities:123")).to be_nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#find" do
|
43
|
+
it "finds the entity based on the id from the redis store" do
|
44
|
+
subject.create entity
|
45
|
+
result = subject.find entity.id
|
46
|
+
|
47
|
+
expect(result.id).to eq entity.id
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns nil if the entity can't be found" do
|
51
|
+
result = subject.find 789
|
52
|
+
|
53
|
+
expect(result).to be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#persist" do
|
58
|
+
it "creates the entity if it's new" do
|
59
|
+
entity = Entity.new id: 531
|
60
|
+
result = subject.persist entity
|
61
|
+
|
62
|
+
expect(result).to eq entity
|
63
|
+
expect(@redis.get("entities:531")).to eq(JSON.generate({ blah: nil }))
|
64
|
+
end
|
65
|
+
|
66
|
+
it "updates the entity if it exists" do
|
67
|
+
created = subject.create entity
|
68
|
+
created.blah = "bleh"
|
69
|
+
result = subject.persist created
|
70
|
+
|
71
|
+
expect(result).to eq entity
|
72
|
+
expect(@redis.get("entities:123")).to eq(JSON.generate({ blah: "bleh" }))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#update" do
|
77
|
+
it "updates the entity in the redis store" do
|
78
|
+
created = subject.create entity
|
79
|
+
created.blah = "bleh"
|
80
|
+
result = subject.update created
|
81
|
+
|
82
|
+
expect(result).to eq entity
|
83
|
+
expect(@redis.get("entities:123")).to eq(JSON.generate({ blah: "bleh" }))
|
84
|
+
end
|
85
|
+
|
86
|
+
it "throws an exception if the entity is not already stored" do
|
87
|
+
entity = Entity.new id: 456
|
88
|
+
|
89
|
+
expect { subject.update entity }.to raise_error Juvet::EntityNotFoundError
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
describe Juvet::Attributable do
|
2
|
+
class Ava
|
3
|
+
include Juvet::Attributable
|
4
|
+
end
|
5
|
+
|
6
|
+
describe "#attributes" do
|
7
|
+
subject { Ava.new name: "Ava", model: 5.9 }
|
8
|
+
|
9
|
+
it "returns a hash of the objects public getters and their values" do
|
10
|
+
expect(subject.attributes).to eq({ name: "Ava", model: 5.9 })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#initialize" do
|
15
|
+
it "has a default initializer to accept attributes" do
|
16
|
+
expect { Ava.new name: "Ava" }.to_not raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#initialize!" do
|
21
|
+
subject { Ava.new name: "Ava", age: nil }
|
22
|
+
|
23
|
+
it "initializes instance variables" do
|
24
|
+
expect(subject.instance_variable_get("@name")).to eq "Ava"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does not override any existing instance variables" do
|
28
|
+
subject = Ava.new name: "Ava"
|
29
|
+
subject.instance_variable_set "@name", "Blah"
|
30
|
+
subject.initialize! name: "Ava"
|
31
|
+
|
32
|
+
expect(subject.instance_variable_get("@name")).to eq "Blah"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#attribute!" do
|
37
|
+
subject { Ava.new name: "Ava", age: nil }
|
38
|
+
|
39
|
+
it "defines the getters for the attributes" do
|
40
|
+
expect(subject).to respond_to :name
|
41
|
+
end
|
42
|
+
|
43
|
+
it "responds to the getters" do
|
44
|
+
expect(subject.name).to eq "Ava"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "does not override existing getters" do
|
48
|
+
class Ava
|
49
|
+
include Juvet::Attributable
|
50
|
+
|
51
|
+
def name
|
52
|
+
"Blah"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
subject = Ava.new name: "Ava"
|
56
|
+
|
57
|
+
expect(subject.name).to eq "Blah"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "defines the setters for the attributes" do
|
61
|
+
expect(subject).to respond_to :age=
|
62
|
+
end
|
63
|
+
|
64
|
+
it "has working setters" do
|
65
|
+
subject.age = 21
|
66
|
+
expect(subject.age).to eq 21
|
67
|
+
end
|
68
|
+
|
69
|
+
it "does not override existing setters" do
|
70
|
+
class Foo
|
71
|
+
include Juvet::Attributable
|
72
|
+
attr_reader :real_name
|
73
|
+
|
74
|
+
def name=(value)
|
75
|
+
@real_name = value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
subject = Foo.new name: "Ava"
|
79
|
+
subject.name = "Athena"
|
80
|
+
|
81
|
+
expect(subject.real_name).to eq "Athena"
|
82
|
+
expect(subject.name).to eq "Ava"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
describe Juvet::Bot do
|
2
|
+
describe ".create" do
|
3
|
+
subject do
|
4
|
+
described_class.create "xoxb-blah", team_id: "Blah",
|
5
|
+
name: "blah"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "creates an instance of the class" do
|
9
|
+
expect(subject).to be_an_instance_of described_class
|
10
|
+
end
|
11
|
+
|
12
|
+
it "assigns the id" do
|
13
|
+
expect(subject.id).to eq "xoxb-blah"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "defines getters for the attributes" do
|
17
|
+
expect(subject.team_id).to eq "Blah"
|
18
|
+
expect(subject.name).to eq "blah"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "defines setters for the attributes" do
|
22
|
+
subject.name = "Thor!"
|
23
|
+
|
24
|
+
expect(subject.name).to eq "Thor!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".create!" do
|
29
|
+
it "stores the created instance in the repository" do
|
30
|
+
expect(Juvet::BotRepository).to receive(:create).with Juvet::Bot
|
31
|
+
described_class.create! "blah", name: "blah"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".destroy!" do
|
36
|
+
let!(:bot) { described_class.create! "xoxb-blah", team_id: "Blah" }
|
37
|
+
|
38
|
+
it "removes the instance from the repository" do
|
39
|
+
expect(Juvet::BotRepository).to receive(:destroy).with "xoxb-blah"
|
40
|
+
described_class.destroy! bot.id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".find" do
|
45
|
+
let!(:bot) { described_class.create! "xoxb-blah", team_id: "Blah" }
|
46
|
+
|
47
|
+
it "creates an instance from the repository" do
|
48
|
+
expect(Juvet::BotRepository).to receive(:find).with "xoxb-blah"
|
49
|
+
described_class.find! bot.id
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#update!" do
|
54
|
+
let!(:bot) { described_class.create! "xoxb-blah", team_id: "Blah" }
|
55
|
+
|
56
|
+
it "updates the instance in the repository" do
|
57
|
+
expect(Juvet::BotRepository).to receive(:update).with bot
|
58
|
+
bot.update! team_id: "Bleh"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
describe Juvet::Configuration::Adapter do
|
2
|
+
describe "#type" do
|
3
|
+
it "sets the type from the options" do
|
4
|
+
subject = described_class.new type: :null
|
5
|
+
expect(subject.type).to eq :null
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#options" do
|
10
|
+
it "includes any additional options initialized" do
|
11
|
+
subject = described_class.new type: :nil, blah: :bleh
|
12
|
+
expect(subject.options).to eq({ blah: :bleh })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#class_name" do
|
17
|
+
it "creates a class name from the type" do
|
18
|
+
subject = described_class.new type: :null
|
19
|
+
expect(subject.class_name).to eq "NullAdapter"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#build" do
|
24
|
+
let(:mapper) { double(:mapper, collection_for_repository: nil) }
|
25
|
+
subject { described_class.new type: :null }
|
26
|
+
|
27
|
+
it "creates an instance of the adapter" do
|
28
|
+
adapter = subject.build mapper
|
29
|
+
|
30
|
+
expect(adapter).to be_instance_of Juvet::Adapters::NullAdapter
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns a load error if the adapter type cannot be loaded" do
|
34
|
+
subject = described_class.new type: :blah
|
35
|
+
|
36
|
+
expect { subject.build(mapper) }.to raise_error LoadError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe Juvet::Configuration::Mapping do
|
2
|
+
describe "#build" do
|
3
|
+
let(:blk) do
|
4
|
+
Proc.new {
|
5
|
+
collection :widgets do
|
6
|
+
end
|
7
|
+
}
|
8
|
+
end
|
9
|
+
subject { described_class.new &blk }
|
10
|
+
|
11
|
+
it "creates a mapper from a block" do
|
12
|
+
result = subject.build
|
13
|
+
|
14
|
+
expect(result).to be_an_instance_of Juvet::Mapper
|
15
|
+
expect(result.collections.length).to eq 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe Juvet::Configuration do
|
2
|
+
subject { described_class.new }
|
3
|
+
|
4
|
+
it "has a default repository adapter" do
|
5
|
+
subject.adapter = nil
|
6
|
+
expect(subject.adapter).to be_instance_of Juvet::Configuration::Adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has a default mapping" do
|
10
|
+
expect(subject.mapping).to be_instance_of Juvet::Configuration::Mapping
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#load!" do
|
14
|
+
subject { described_class.new }
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
subject.adapter = { type: :null }
|
18
|
+
subject.mapping do; end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "builds the mapping" do
|
22
|
+
expect(subject.mapping).to receive(:build).and_call_original
|
23
|
+
subject.load!
|
24
|
+
end
|
25
|
+
|
26
|
+
it "builds the adapter" do
|
27
|
+
expect(subject.adapter).to receive(:build).with(Juvet::Mapper)
|
28
|
+
subject.load!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Juvet::Mapper::Collection do
|
2
|
+
describe "#initialize" do
|
3
|
+
it "provides a name" do
|
4
|
+
subject = described_class.new :widgets
|
5
|
+
|
6
|
+
expect(subject.name).to eq :widgets
|
7
|
+
end
|
8
|
+
|
9
|
+
it "executes the block if one is provided" do
|
10
|
+
subject = described_class.new(:widgets) do
|
11
|
+
entity Object
|
12
|
+
repository Object
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(subject.entity).to eq Object
|
16
|
+
expect(subject.repository).to eq Object
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
describe Juvet::Mapper do
|
2
|
+
describe "#initialize" do
|
3
|
+
it "generates collections based on the block" do
|
4
|
+
subject = described_class.new do
|
5
|
+
collection :widgets do; end
|
6
|
+
end
|
7
|
+
|
8
|
+
expect(subject.collections.length).to eq 1
|
9
|
+
expect(subject.collections).to have_key :widgets
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#collection" do
|
14
|
+
subject { described_class.new }
|
15
|
+
|
16
|
+
it "adds a collection with the block" do
|
17
|
+
subject.collection(:widgets) do; end
|
18
|
+
|
19
|
+
expect(subject.collections[:widgets]).to \
|
20
|
+
be_instance_of Juvet::Mapper::Collection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#collection_for_repository" do
|
25
|
+
class WidgetRepository; end
|
26
|
+
let(:subject) do
|
27
|
+
described_class.new do
|
28
|
+
collection :widgets do
|
29
|
+
repository WidgetRepository
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the collection for the first one that specifies the repository" do
|
35
|
+
result = subject.collection_for_repository WidgetRepository
|
36
|
+
|
37
|
+
expect(result.name).to eq :widgets
|
38
|
+
expect(result.repository).to eq WidgetRepository
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil if the repository is not found" do
|
42
|
+
result = subject.collection_for_repository Object
|
43
|
+
|
44
|
+
expect(result).to be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
describe Juvet::Repository do
|
2
|
+
class Repository
|
3
|
+
include Juvet::Repository
|
4
|
+
end
|
5
|
+
|
6
|
+
it "defaults to using the NullAdapter" do
|
7
|
+
expect(Repository.adapter).to be_instance_of Juvet::Adapters::NullAdapter
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".create" do
|
11
|
+
it "passes creation to the adapter" do
|
12
|
+
object = Object.new
|
13
|
+
expect(Repository.adapter).to receive(:create).with object
|
14
|
+
Repository.create object
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".destroy" do
|
19
|
+
it "passes the destroying to the adapter" do
|
20
|
+
id = "123"
|
21
|
+
expect(Repository.adapter).to receive(:destroy).with id
|
22
|
+
Repository.destroy id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".find" do
|
27
|
+
it "passes the finding to the adapter" do
|
28
|
+
id = "123"
|
29
|
+
expect(Repository.adapter).to receive(:find).with id
|
30
|
+
Repository.find id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe ".persist" do
|
35
|
+
it "passes persitance to the adapter" do
|
36
|
+
object = Object.new
|
37
|
+
expect(Repository.adapter).to receive(:persist).with object
|
38
|
+
Repository.persist object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".update" do
|
43
|
+
it "passes updating to the adapter" do
|
44
|
+
object = Object.new
|
45
|
+
expect(Repository.adapter).to receive(:update).with object
|
46
|
+
Repository.update object
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe Juvet::String do
|
2
|
+
describe "#classify" do
|
3
|
+
it "converts an underscored string to a camel case word" do
|
4
|
+
expect(described_class.new("this_is_fine").classify).to eq "ThisIsFine"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#underscore" do
|
9
|
+
it "converts camel case to underscore" do
|
10
|
+
expect(described_class.new("ThisIsFine").underscore).to eq "this_is_fine"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/juvet_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
describe Juvet do
|
2
|
+
describe ".configuration" do
|
3
|
+
it "returns a new instance of the configuration" do
|
4
|
+
expect(described_class.configuration).to be_instance_of Juvet::Configuration
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".configure" do
|
9
|
+
it "yields configuration" do
|
10
|
+
allow(described_class.configuration).to receive(:load!)
|
11
|
+
expect { |b| described_class.configure &b }.to \
|
12
|
+
yield_with_args Juvet::Configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
it "loads the configuration" do
|
16
|
+
expect(described_class.configuration).to receive(:load!)
|
17
|
+
described_class.configure
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "juvet"
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.expect_with :rspec do |expectations|
|
5
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
6
|
+
end
|
7
|
+
|
8
|
+
config.mock_with :rspec do |mocks|
|
9
|
+
mocks.verify_partial_doubles = true
|
10
|
+
end
|
11
|
+
|
12
|
+
config.filter_run :focus
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: juvet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jamie Wright
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: A factory and storage mechanism to store your bot information, backed
|
28
|
+
by Redis.
|
29
|
+
email:
|
30
|
+
- jamie@tatsu.io
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- ".rspec"
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- LICENSE.md
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- juvet.gemspec
|
43
|
+
- lib/juvet.rb
|
44
|
+
- lib/juvet/adapters/null_adapter.rb
|
45
|
+
- lib/juvet/adapters/redis_adapter.rb
|
46
|
+
- lib/juvet/attributable.rb
|
47
|
+
- lib/juvet/bot.rb
|
48
|
+
- lib/juvet/bot_repository.rb
|
49
|
+
- lib/juvet/configuration.rb
|
50
|
+
- lib/juvet/configuration/adapter.rb
|
51
|
+
- lib/juvet/configuration/mapping.rb
|
52
|
+
- lib/juvet/entity_not_found_error.rb
|
53
|
+
- lib/juvet/mapper.rb
|
54
|
+
- lib/juvet/mapper/collection.rb
|
55
|
+
- lib/juvet/repository.rb
|
56
|
+
- lib/juvet/string.rb
|
57
|
+
- lib/juvet/version.rb
|
58
|
+
- spec/juvet/adapters/null_adapter_spec.rb
|
59
|
+
- spec/juvet/adapters/redis_adapter_spec.rb
|
60
|
+
- spec/juvet/attributable_spec.rb
|
61
|
+
- spec/juvet/bot_spec.rb
|
62
|
+
- spec/juvet/configuration/adapter_spec.rb
|
63
|
+
- spec/juvet/configuration/mapping_spec.rb
|
64
|
+
- spec/juvet/configuration_spec.rb
|
65
|
+
- spec/juvet/mapper/collection_spec.rb
|
66
|
+
- spec/juvet/mapper_spec.rb
|
67
|
+
- spec/juvet/repository_spec.rb
|
68
|
+
- spec/juvet/string_spec.rb
|
69
|
+
- spec/juvet_spec.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
homepage: http://github.com/tatsuio/juvet
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '2.2'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.5.1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: The factory for bots.
|
95
|
+
test_files:
|
96
|
+
- spec/juvet/adapters/null_adapter_spec.rb
|
97
|
+
- spec/juvet/adapters/redis_adapter_spec.rb
|
98
|
+
- spec/juvet/attributable_spec.rb
|
99
|
+
- spec/juvet/bot_spec.rb
|
100
|
+
- spec/juvet/configuration/adapter_spec.rb
|
101
|
+
- spec/juvet/configuration/mapping_spec.rb
|
102
|
+
- spec/juvet/configuration_spec.rb
|
103
|
+
- spec/juvet/mapper/collection_spec.rb
|
104
|
+
- spec/juvet/mapper_spec.rb
|
105
|
+
- spec/juvet/repository_spec.rb
|
106
|
+
- spec/juvet/string_spec.rb
|
107
|
+
- spec/juvet_spec.rb
|
108
|
+
- spec/spec_helper.rb
|