scales-core 0.0.1.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|