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.
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