scales-core 0.0.1.beta.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/bin/scale +14 -0
- data/bin/scalify +6 -0
- data/lib/.DS_Store +0 -0
- data/lib/scales-core.rb +13 -0
- data/lib/scales-core/.DS_Store +0 -0
- data/lib/scales-core/base.rb +31 -0
- data/lib/scales-core/boot/autoload.rb +19 -0
- data/lib/scales-core/boot/initializers/em.rb +3 -0
- data/lib/scales-core/boot/initializers/goliath.rb +2 -0
- data/lib/scales-core/boot/initializers/json.rb +1 -0
- data/lib/scales-core/boot/initializers/redis.rb +1 -0
- data/lib/scales-core/boot/initializers/securerandom.rb +1 -0
- data/lib/scales-core/boot/initializers/thor.rb +1 -0
- data/lib/scales-core/config.rb +46 -0
- data/lib/scales-core/helper.rb +6 -0
- data/lib/scales-core/helper/content_types.rb +29 -0
- data/lib/scales-core/helper/partial_resolver.rb +36 -0
- data/lib/scales-core/pub_sub.rb +6 -0
- data/lib/scales-core/pub_sub/async.rb +19 -0
- data/lib/scales-core/pub_sub/sync.rb +17 -0
- data/lib/scales-core/queue.rb +8 -0
- data/lib/scales-core/queue/async.rb +18 -0
- data/lib/scales-core/queue/sync.rb +18 -0
- data/lib/scales-core/scalify.rb +17 -0
- data/lib/scales-core/scalify/templates/cache.yml +20 -0
- data/lib/scales-core/scalify/templates/scaleup.rb +6 -0
- data/lib/scales-core/storage.rb +17 -0
- data/lib/scales-core/storage/async.rb +89 -0
- data/lib/scales-core/storage/sync.rb +93 -0
- data/lib/scales-core/version.rb +5 -0
- data/scales-core.gemspec +29 -0
- data/spec/.DS_Store +0 -0
- data/spec/base_spec.rb +19 -0
- data/spec/config_spec.rb +43 -0
- data/spec/gem_spec.rb +7 -0
- data/spec/helper.rb +57 -0
- data/spec/partial_resolver_spec.rb +45 -0
- data/spec/pub_sub_spec.rb +51 -0
- data/spec/queue_spec.rb +37 -0
- data/spec/scalify_spec.rb +13 -0
- data/spec/storage_spec.rb +147 -0
- metadata +213 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
development:
|
2
|
+
host: localhost
|
3
|
+
port: 6379
|
4
|
+
password:
|
5
|
+
database: 1
|
6
|
+
partials: false
|
7
|
+
|
8
|
+
test:
|
9
|
+
host: localhost
|
10
|
+
port: 6379
|
11
|
+
password:
|
12
|
+
database: 2
|
13
|
+
partials: false
|
14
|
+
|
15
|
+
production:
|
16
|
+
host: localhost
|
17
|
+
port: 6379
|
18
|
+
password:
|
19
|
+
database: 0
|
20
|
+
partials: false
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Scales
|
2
|
+
module Storage
|
3
|
+
RESOURCE_PREFIX = "scales_resource_"
|
4
|
+
PARTIAL_PREFIX = "scales_partial_"
|
5
|
+
|
6
|
+
autoload :Sync, "scales-core/storage/sync"
|
7
|
+
autoload :Async, "scales-core/storage/async"
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def prefix(path)
|
12
|
+
(path =~ /^\//) ? RESOURCE_PREFIX + path : PARTIAL_PREFIX + path
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Scales
|
2
|
+
module Storage
|
3
|
+
module Async
|
4
|
+
@@redis = nil
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def connect!
|
9
|
+
return if @@redis and @@redis.connected?
|
10
|
+
@@redis = new_connection!
|
11
|
+
end
|
12
|
+
|
13
|
+
def force_reconnect!
|
14
|
+
@@redis = new_connection!
|
15
|
+
end
|
16
|
+
|
17
|
+
def connection
|
18
|
+
with_connection{ @@redis }
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_content(path, value)
|
22
|
+
set(Storage.prefix(path), value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_content(path, partials = false)
|
26
|
+
get(Storage.prefix(path), partials)
|
27
|
+
end
|
28
|
+
|
29
|
+
def del_content(path)
|
30
|
+
del(Storage.prefix(path))
|
31
|
+
end
|
32
|
+
|
33
|
+
def set(key, value)
|
34
|
+
with_connection{ @@redis.set(key, value) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def get(key, partials = false)
|
38
|
+
with_connection{ partials ? Helper::PartialResolver.resolve(@@redis, key) : @@redis.get(key) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def del(key)
|
42
|
+
with_connection{ @@redis.del(key) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def add(queue, job)
|
46
|
+
with_connection{ @@redis.lpush(queue, job) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def pop(queue)
|
50
|
+
with_new_connection{ |redis| redis.brpop(queue, 0) }.last
|
51
|
+
end
|
52
|
+
|
53
|
+
def publish(channel, message)
|
54
|
+
add(channel, message)
|
55
|
+
end
|
56
|
+
|
57
|
+
def subscribe(channel)
|
58
|
+
pop(channel)
|
59
|
+
end
|
60
|
+
|
61
|
+
def flushall!
|
62
|
+
with_connection{ @@redis.flushall }
|
63
|
+
end
|
64
|
+
|
65
|
+
def new_connection!
|
66
|
+
EM::Hiredis.connect "redis://:#{Scales.config.password}@#{Scales.config.host}:#{Scales.config.port}/#{Scales.config.database}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def with_connection
|
72
|
+
connect!
|
73
|
+
yield
|
74
|
+
end
|
75
|
+
|
76
|
+
# Creates a new connection for blocking calls and closes it after the block
|
77
|
+
def with_new_connection
|
78
|
+
redis = new_connection!
|
79
|
+
out = yield(redis)
|
80
|
+
redis.quit
|
81
|
+
redis = nil
|
82
|
+
out
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Scales
|
2
|
+
module Storage
|
3
|
+
module Sync
|
4
|
+
@@redis = nil
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def connect!
|
9
|
+
return if @@redis && @@redis.client.connected?
|
10
|
+
@@redis = new_connection!
|
11
|
+
end
|
12
|
+
|
13
|
+
def force_reconnect!
|
14
|
+
@@redis = new_connection!
|
15
|
+
end
|
16
|
+
|
17
|
+
def connection
|
18
|
+
with_connection{ @@redis }
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_content(path, value)
|
22
|
+
set(Storage.prefix(path), value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_content(path, partials = false)
|
26
|
+
get(Storage.prefix(path), partials)
|
27
|
+
end
|
28
|
+
|
29
|
+
def del_content(path)
|
30
|
+
del(Storage.prefix(path))
|
31
|
+
end
|
32
|
+
|
33
|
+
def set(key, value)
|
34
|
+
with_connection{ @@redis.set(key, value) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def get(key, partials = false)
|
38
|
+
with_connection{ partials ? Helper::PartialResolver.resolve(@@redis, key) : @@redis.get(key) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def del(key)
|
42
|
+
with_connection{ @@redis.del(key) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def add(queue, job)
|
46
|
+
with_connection{ @@redis.lpush(queue, job) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def pop(queue)
|
50
|
+
with_new_connection{ |redis| redis.brpop(queue, 0) }.last
|
51
|
+
end
|
52
|
+
|
53
|
+
def publish(channel, message)
|
54
|
+
add(channel, message)
|
55
|
+
end
|
56
|
+
|
57
|
+
def subscribe(channel)
|
58
|
+
pop(channel)
|
59
|
+
end
|
60
|
+
|
61
|
+
def flushall!
|
62
|
+
with_connection{ @@redis.flushall }
|
63
|
+
end
|
64
|
+
|
65
|
+
def new_connection!
|
66
|
+
Redis.new(
|
67
|
+
:host => Scales.config.host,
|
68
|
+
:port => Scales.config.port,
|
69
|
+
:password => Scales.config.password,
|
70
|
+
:db => Scales.config.database
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def with_connection
|
77
|
+
connect!
|
78
|
+
yield
|
79
|
+
end
|
80
|
+
|
81
|
+
# Creates a new connection for blocking calls and closes it after the block
|
82
|
+
def with_new_connection
|
83
|
+
redis = new_connection!
|
84
|
+
out = yield(redis)
|
85
|
+
redis.quit
|
86
|
+
redis = nil
|
87
|
+
out
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/scales-core.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/scales-core/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Thomas Fankhauser"]
|
6
|
+
gem.email = ["tommylefunk@googlemail.com"]
|
7
|
+
gem.description = %q{Super Scale Caching Framework - Core}
|
8
|
+
gem.summary = %q{Provides core functionalities like storage, queues, pubsub and configurations.}
|
9
|
+
gem.homepage = "http://itscales.org"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "scales-core"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Scales::Core::VERSION
|
17
|
+
|
18
|
+
# Dependencies
|
19
|
+
gem.add_dependency "rake", ">= 0.9.2.2"
|
20
|
+
gem.add_dependency "rspec", ">= 2.11"
|
21
|
+
gem.add_dependency "redis", ">= 3.0.1"
|
22
|
+
gem.add_dependency "eventmachine", ">= 1.0.0.beta.4"
|
23
|
+
gem.add_dependency "em-http-request", ">= 1.0.2"
|
24
|
+
gem.add_dependency "em-synchrony", ">= 1.0.2"
|
25
|
+
gem.add_dependency "em-hiredis", ">= 0.1.1"
|
26
|
+
gem.add_dependency "json", ">= 1.7.4"
|
27
|
+
gem.add_dependency "colorize", ">= 0.5.8"
|
28
|
+
gem.add_dependency "thor", ">= 0.15.4"
|
29
|
+
end
|
data/spec/.DS_Store
ADDED
Binary file
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Scales do
|
4
|
+
|
5
|
+
it "tries to set the env" do
|
6
|
+
Scales.env = nil
|
7
|
+
ARGV = ["test"]
|
8
|
+
Scales.try_to_setup_env!
|
9
|
+
Scales.env.should == "test"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "ignores env with options" do
|
13
|
+
Scales.env = nil
|
14
|
+
ARGV = ["-o"]
|
15
|
+
Scales.try_to_setup_env!
|
16
|
+
Scales.env.should == "development"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Scales::Config do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
described_class.reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have default values" do
|
10
|
+
Scales.config.should_not be_nil
|
11
|
+
Scales.config.host.should == "localhost"
|
12
|
+
Scales.config.port.should == 6379
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to write new values" do
|
16
|
+
Scales.config.test.should be_nil
|
17
|
+
Scales.config.test = "a new values"
|
18
|
+
Scales.config.test.should == "a new values"
|
19
|
+
end
|
20
|
+
|
21
|
+
context "loading cache.yml" do
|
22
|
+
|
23
|
+
it "loads cache.yml if it exists" do
|
24
|
+
in_app_folder do
|
25
|
+
Scales.env = "production"
|
26
|
+
Scales.config.host.should == "123.123.123.123"
|
27
|
+
Scales.config.port.should == 6380
|
28
|
+
Scales.config.password.should == "secret"
|
29
|
+
Scales.config.database.should == 5
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sticks with the defaults if it doesn't" do
|
34
|
+
Scales.env = "production"
|
35
|
+
Scales.config.host.should == "localhost"
|
36
|
+
Scales.config.port.should == 6379
|
37
|
+
Scales.config.password.should be_nil
|
38
|
+
Scales.config.database.should == 0
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/spec/gem_spec.rb
ADDED
data/spec/helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'scales-core'
|
2
|
+
|
3
|
+
Scales.env = "test"
|
4
|
+
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
def async
|
8
|
+
if EM.reactor_running?
|
9
|
+
yield
|
10
|
+
else
|
11
|
+
out = nil
|
12
|
+
EM.synchrony do
|
13
|
+
out = yield
|
14
|
+
EM.stop
|
15
|
+
end
|
16
|
+
out
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def fixture(file)
|
21
|
+
File.read(File.expand_path("../fixtures/#{file}", __FILE__))
|
22
|
+
end
|
23
|
+
|
24
|
+
def in_app_folder
|
25
|
+
pwd = Dir.pwd
|
26
|
+
Dir.chdir File.expand_path("../../../spec/app", __FILE__)
|
27
|
+
yield
|
28
|
+
Dir.chdir(pwd)
|
29
|
+
end
|
30
|
+
|
31
|
+
def in_temp_folder
|
32
|
+
pwd = Dir.pwd
|
33
|
+
Dir.mkdir "spec/tmp"
|
34
|
+
Dir.chdir "spec/tmp"
|
35
|
+
begin
|
36
|
+
yield
|
37
|
+
rescue Exception => e
|
38
|
+
raise e
|
39
|
+
ensure
|
40
|
+
Dir.chdir(pwd)
|
41
|
+
FileUtils.rm_rf("spec/tmp")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def squeeze string
|
46
|
+
string.gsub(/(\n|\t|\r)/, ' ').gsub(/>\s*</, '><').squeeze(' ').strip
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
RSpec.configure do |config|
|
52
|
+
config.include Helpers
|
53
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
54
|
+
config.before(:suite) do
|
55
|
+
Scales::Storage::Sync.flushall!
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Scales::Helper::PartialResolver do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@html = <<-HTML
|
7
|
+
<html>
|
8
|
+
<body>
|
9
|
+
<div id="header">Scales.partial "header"</div>
|
10
|
+
<div id="page">
|
11
|
+
<h1>Hello World</h1>
|
12
|
+
</div>
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
HTML
|
16
|
+
|
17
|
+
@header = "<div>Header with Items: <div>Scales.partial 'items'</div></div>"
|
18
|
+
@items = "<ul><li>Item 1</li><li>Item 2</li></ul>"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "checks if a string includes a partial" do
|
22
|
+
described_class.includes_partial?('Scales.partial "header"').should be_true
|
23
|
+
described_class.includes_partial?("Scales.partial 'header'").should be_true
|
24
|
+
described_class.includes_partial?(@html).should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns value if key doesn't contain a partial" do
|
28
|
+
Scales::Storage::Sync.set_content "/tracks", "A text without partials"
|
29
|
+
described_class.resolve(Scales::Storage::Sync.connection, "scales_resource_/tracks").should == "A text without partials"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "resolves a partial" do
|
33
|
+
Scales::Storage::Sync.set_content "header", "<p>The header</p>"
|
34
|
+
described_class.resolve_partial(Scales::Storage::Sync.connection, @html).should == @html.gsub('Scales.partial "header"', "<p>The header</p>")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "multi resolves partials" do
|
38
|
+
Scales::Storage::Sync.set_content "/tracks", @html
|
39
|
+
Scales::Storage::Sync.set_content "header", @header
|
40
|
+
Scales::Storage::Sync.set_content "items", @items
|
41
|
+
|
42
|
+
described_class.resolve(Scales::Storage::Sync.connection, "scales_resource_/tracks").should == @html.gsub('Scales.partial "header"', @header).gsub("Scales.partial 'items'", @items)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|