scales-core 0.0.1.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +8 -0
  6. data/bin/scale +14 -0
  7. data/bin/scalify +6 -0
  8. data/lib/.DS_Store +0 -0
  9. data/lib/scales-core.rb +13 -0
  10. data/lib/scales-core/.DS_Store +0 -0
  11. data/lib/scales-core/base.rb +31 -0
  12. data/lib/scales-core/boot/autoload.rb +19 -0
  13. data/lib/scales-core/boot/initializers/em.rb +3 -0
  14. data/lib/scales-core/boot/initializers/goliath.rb +2 -0
  15. data/lib/scales-core/boot/initializers/json.rb +1 -0
  16. data/lib/scales-core/boot/initializers/redis.rb +1 -0
  17. data/lib/scales-core/boot/initializers/securerandom.rb +1 -0
  18. data/lib/scales-core/boot/initializers/thor.rb +1 -0
  19. data/lib/scales-core/config.rb +46 -0
  20. data/lib/scales-core/helper.rb +6 -0
  21. data/lib/scales-core/helper/content_types.rb +29 -0
  22. data/lib/scales-core/helper/partial_resolver.rb +36 -0
  23. data/lib/scales-core/pub_sub.rb +6 -0
  24. data/lib/scales-core/pub_sub/async.rb +19 -0
  25. data/lib/scales-core/pub_sub/sync.rb +17 -0
  26. data/lib/scales-core/queue.rb +8 -0
  27. data/lib/scales-core/queue/async.rb +18 -0
  28. data/lib/scales-core/queue/sync.rb +18 -0
  29. data/lib/scales-core/scalify.rb +17 -0
  30. data/lib/scales-core/scalify/templates/cache.yml +20 -0
  31. data/lib/scales-core/scalify/templates/scaleup.rb +6 -0
  32. data/lib/scales-core/storage.rb +17 -0
  33. data/lib/scales-core/storage/async.rb +89 -0
  34. data/lib/scales-core/storage/sync.rb +93 -0
  35. data/lib/scales-core/version.rb +5 -0
  36. data/scales-core.gemspec +29 -0
  37. data/spec/.DS_Store +0 -0
  38. data/spec/base_spec.rb +19 -0
  39. data/spec/config_spec.rb +43 -0
  40. data/spec/gem_spec.rb +7 -0
  41. data/spec/helper.rb +57 -0
  42. data/spec/partial_resolver_spec.rb +45 -0
  43. data/spec/pub_sub_spec.rb +51 -0
  44. data/spec/queue_spec.rb +37 -0
  45. data/spec/scalify_spec.rb +13 -0
  46. data/spec/storage_spec.rb +147 -0
  47. 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,6 @@
1
+ require 'scales/up/rails'
2
+
3
+ desc "Scale up the cache"
4
+ Scales::Up.new do |scales|
5
+ # Heat it up ...
6
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ module Scales
2
+ module Core
3
+ VERSION = "0.0.1.beta.1"
4
+ end
5
+ end
@@ -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
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ describe Scales::Core do
4
+ it "should have a version" do
5
+ Scales::Core::VERSION.should_not be_nil
6
+ end
7
+ end
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