circuit 0.2.0

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 (75) hide show
  1. data/Gemfile +34 -0
  2. data/LICENSE +20 -0
  3. data/README.md +161 -0
  4. data/Rakefile +27 -0
  5. data/config.ru +7 -0
  6. data/description.md +5 -0
  7. data/docs/COMPATIBILITY.md +14 -0
  8. data/docs/ROADMAP.md +29 -0
  9. data/lib/circuit.rb +125 -0
  10. data/lib/circuit/behavior.rb +99 -0
  11. data/lib/circuit/compatibility.rb +73 -0
  12. data/lib/circuit/middleware.rb +6 -0
  13. data/lib/circuit/middleware/rewriter.rb +43 -0
  14. data/lib/circuit/rack.rb +14 -0
  15. data/lib/circuit/rack/behavioral.rb +45 -0
  16. data/lib/circuit/rack/builder.rb +50 -0
  17. data/lib/circuit/rack/multi_site.rb +22 -0
  18. data/lib/circuit/rack/request.rb +81 -0
  19. data/lib/circuit/railtie.rb +24 -0
  20. data/lib/circuit/storage.rb +74 -0
  21. data/lib/circuit/storage/memory_model.rb +70 -0
  22. data/lib/circuit/storage/nodes.rb +56 -0
  23. data/lib/circuit/storage/nodes/memory_store.rb +63 -0
  24. data/lib/circuit/storage/nodes/model.rb +67 -0
  25. data/lib/circuit/storage/nodes/mongoid_store.rb +56 -0
  26. data/lib/circuit/storage/sites.rb +38 -0
  27. data/lib/circuit/storage/sites/memory_store.rb +53 -0
  28. data/lib/circuit/storage/sites/model.rb +29 -0
  29. data/lib/circuit/storage/sites/mongoid_store.rb +43 -0
  30. data/lib/circuit/validators.rb +74 -0
  31. data/lib/circuit/version.rb +3 -0
  32. data/spec/internal/app/behaviors/change_path.rb +7 -0
  33. data/spec/internal/app/controllers/application_controller.rb +5 -0
  34. data/spec/internal/app/helpers/application_helper.rb +2 -0
  35. data/spec/internal/config/initializers/circuit.rb +7 -0
  36. data/spec/internal/config/routes.rb +3 -0
  37. data/spec/internal/db/schema.rb +1 -0
  38. data/spec/lib/circuit/behavior_spec.rb +113 -0
  39. data/spec/lib/circuit/middleware/rewriter_spec.rb +79 -0
  40. data/spec/lib/circuit/rack/behavioral_spec.rb +60 -0
  41. data/spec/lib/circuit/rack/builder_spec.rb +125 -0
  42. data/spec/lib/circuit/rack/multi_site_spec.rb +34 -0
  43. data/spec/lib/circuit/rack/request_spec.rb +80 -0
  44. data/spec/lib/circuit/railtie_spec.rb +34 -0
  45. data/spec/lib/circuit/storage/nodes_spec.rb +62 -0
  46. data/spec/lib/circuit/storage/sites_spec.rb +60 -0
  47. data/spec/lib/circuit/storage_spec.rb +20 -0
  48. data/spec/lib/circuit/validators_spec.rb +69 -0
  49. data/spec/lib/circuit_spec.rb +139 -0
  50. data/spec/spec_helper.rb +79 -0
  51. data/spec/support/blueprints.rb +24 -0
  52. data/spec/support/matchers/be_current_time_matcher.rb +14 -0
  53. data/spec/support/matchers/extended_have_key.rb +31 -0
  54. data/spec/support/matchers/have_accessor_matcher.rb +13 -0
  55. data/spec/support/matchers/have_attribute_matcher.rb +22 -0
  56. data/spec/support/matchers/have_block_matcher.rb +14 -0
  57. data/spec/support/matchers/have_errors_on_matcher.rb +30 -0
  58. data/spec/support/matchers/have_module_matcher.rb +13 -0
  59. data/spec/support/matchers/have_reader_matcher.rb +18 -0
  60. data/spec/support/matchers/have_writer_matcher.rb +18 -0
  61. data/spec/support/matchers/set_instance_variable.rb +32 -0
  62. data/spec/support/spec_helpers/base_behaviors.rb +20 -0
  63. data/spec/support/spec_helpers/base_models.rb +64 -0
  64. data/spec/support/spec_helpers/logger_helpers.rb +58 -0
  65. data/spec/support/spec_helpers/multi_site_helper.rb +48 -0
  66. data/spec/support/spec_helpers/rack_helpers.rb +8 -0
  67. data/spec/support/spec_helpers/shared_examples/node_store.rb +87 -0
  68. data/spec/support/spec_helpers/shared_examples/site_store.rb +76 -0
  69. data/spec/support/spec_helpers/simple_machinable.rb +29 -0
  70. data/spec/support/spec_helpers/stores_cleaner.rb +46 -0
  71. data/vendor/active_support-3.2/core_ext/string/inflections.rb +53 -0
  72. data/vendor/active_support-3.2/inflector/methods.rb +65 -0
  73. data/vendor/rack-1.4/builder.rb +167 -0
  74. data/vendor/rack-1.4/urlmap.rb +96 -0
  75. metadata +238 -0
@@ -0,0 +1,79 @@
1
+ require 'rubygems'
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter "/lib/circuit/version.rb"
5
+ add_filter "/spec/"
6
+ end
7
+
8
+ require 'bundler'
9
+
10
+ require 'simplecov'
11
+ SimpleCov.start
12
+
13
+ required_groups = [:default, :development]
14
+
15
+ # Require gems and attempt to load mongo
16
+ begin
17
+ Bundler.require *(required_groups+[:mongo])
18
+ rescue LoadError
19
+ Bundler.require *required_groups
20
+ end
21
+ # Determine if we want to run tests with mongo (i.e. whether mongo was loaded)
22
+ $mongo_tests = !!Bundler.definition.requested_specs.detect {|s| s.name == "mongo"}
23
+
24
+ require 'combustion'
25
+
26
+ require 'machinist'
27
+ require 'machinist/mongoid' if $mongo_tests
28
+
29
+ Mongoid.load! "spec/internal/config/mongoid.yml" if $mongo_tests
30
+
31
+ Combustion.initialize! :action_controller, :action_view, :sprockets
32
+
33
+ require 'rails/mongoid' if $mongo_tests
34
+ require 'rspec/rails'
35
+ require 'rspec/rails/mocha'
36
+ require 'support/blueprints'
37
+
38
+ # Requires supporting ruby files with custom matchers and macros, etc,
39
+ # in spec/support/ and its subdirectories.
40
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
41
+
42
+ RSpec.configure do |config|
43
+ config.mock_with :mocha
44
+ config.include SpecHelpers::RackHelpers
45
+
46
+ if $mongo_tests
47
+ config.include Mongoid::Matchers
48
+
49
+ config.after(:each) do
50
+ Mongoid.master.collections.select do |collection|
51
+ collection.name !~ /system/
52
+ end.each(&:drop)
53
+ end
54
+
55
+ # Clean up the database
56
+ require 'database_cleaner'
57
+ config.before(:suite) do
58
+ DatabaseCleaner.strategy = :truncation
59
+ DatabaseCleaner.orm = "mongoid"
60
+ end
61
+
62
+ config.before(:each) do
63
+ DatabaseCleaner.clean
64
+ end
65
+ end
66
+
67
+ config.after(:each) do
68
+ Circuit::Storage::Sites::MemoryStore::Site.all.clear
69
+ Circuit::Storage::Nodes::MemoryStore::Node.all.clear
70
+ end
71
+
72
+ config.before(:each) { stub_time! }
73
+ end
74
+
75
+ # freeze time, so time tests appear to run without time passing.
76
+ def stub_time!
77
+ @time = Time.zone.now
78
+ Time.zone.stubs(:now).returns(@time)
79
+ end
@@ -0,0 +1,24 @@
1
+ require 'support/spec_helpers/simple_machinable'
2
+
3
+ module CircuitBlueprints
4
+ def ensure_blueprints
5
+ SimpleMachinable.ensure_machinable(Circuit::Site, Circuit::Node)
6
+
7
+ if Circuit::Site.blueprint.nil?
8
+ Circuit::Site.blueprint do
9
+ host { 'example.org' }
10
+ aliases { %w[www.example.org subdomain.example.com] }
11
+ end
12
+ end
13
+
14
+ if Circuit::Node.blueprint.nil?
15
+ Circuit::Node.blueprint do
16
+ slug { Faker::Lorem.words(rand(3) + 2).join('-') }
17
+ behavior_klass { "RenderOk" }
18
+ end
19
+ end
20
+ end
21
+ module_function :ensure_blueprints
22
+ end
23
+
24
+ CircuitBlueprints.ensure_blueprints
@@ -0,0 +1,14 @@
1
+ RSpec::Matchers.define :be_current_time do
2
+ match do |time|
3
+ # the to is is for rounding errors
4
+ time.try(:utc).to_i == Time.zone.now.utc.to_i
5
+ end
6
+
7
+ failure_message_for_should do |time|
8
+ "#{time.class} should be set to local time"
9
+ end
10
+
11
+ failure_message_for_should_not do |time|
12
+ "#{time.class} should not be set to local time"
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ RSpec::Matchers.define :have_key do |key|
2
+ chain :== do |value|
3
+ @value = value
4
+ end
5
+
6
+ match do |hash|
7
+ @has_key = hash.has_key?(key)
8
+
9
+ if @value
10
+ @has_key && hash[key] == @value
11
+ else
12
+ @has_key
13
+ end
14
+ end
15
+
16
+ failure_message_for_should do |hash|
17
+ if @value
18
+ "#{hash.inspect} should have key #{key.inspect} == #{value.inspect}"
19
+ else
20
+ "#{hash.inspect} should have key #{key.inspect}"
21
+ end
22
+ end
23
+
24
+ failure_message_for_should_not do |model|
25
+ if @value
26
+ "#{hash.inspect} should not have key #{key.inspect} == #{value.inspect}"
27
+ else
28
+ "#{hash.inspect} should not have key #{key.inspect}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ RSpec::Matchers.define :have_accessor do |attribute|
2
+ match do |model|
3
+ model.respond_to?(attribute) and model.respond_to?("#{attribute}=")
4
+ end
5
+
6
+ failure_message_for_should do |model|
7
+ "#{model.class} should have attribute accessor #{attribute.inspect}"
8
+ end
9
+
10
+ failure_message_for_should_not do |model|
11
+ "#{model.class} should not have attribute accessor #{attribute.inspect}"
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ RSpec::Matchers.define :have_attribute do |attribute|
2
+ match do |model|
3
+ if model.respond_to?(attribute) and model.respond_to?("#{attribute}=")
4
+ obj = Object.new
5
+ old = model.send(attribute)
6
+ model.send("#{attribute}=", obj)
7
+ result = (model.attributes[attribute] == obj)
8
+ model.send("#{attribute}=", old)
9
+ result
10
+ else
11
+ false
12
+ end
13
+ end
14
+
15
+ failure_message_for_should do |model|
16
+ "#{model.class} should have attribute accessor #{attribute.inspect}"
17
+ end
18
+
19
+ failure_message_for_should_not do |model|
20
+ "#{model.class} should not have attribute accessor #{attribute.inspect}"
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ RSpec::Matchers.define :have_block do |block_sym|
2
+ match do |template|
3
+ # the to is is for rounding errors
4
+ template.blocks[block_sym]
5
+ end
6
+
7
+ failure_message_for_should do |template|
8
+ "#{template.class} should have block(#{block_sym})"
9
+ end
10
+
11
+ failure_message_for_should_not do |template|
12
+ "#{template.class} should not have block(#{block_sym})"
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # http://solnic.eu/2011/01/14/custom-rspec-2-matchers.html
2
+ RSpec::Matchers.define :have_errors_on do |attribute|
3
+ chain :with_message do |message|
4
+ @message = message
5
+ end
6
+
7
+ match do |model|
8
+ model.valid?
9
+
10
+ @has_errors = !(model.errors[attribute].blank?)
11
+
12
+ if @message
13
+ @has_errors && model.errors[attribute].include?(@message)
14
+ else
15
+ @has_errors
16
+ end
17
+ end
18
+
19
+ failure_message_for_should do |model|
20
+ if @message
21
+ "Validation errors #{model.errors[attribute].inspect} should include #{@message.inspect}"
22
+ else
23
+ "#{model.class} should have errors on attribute #{attribute.inspect}"
24
+ end
25
+ end
26
+
27
+ failure_message_for_should_not do |model|
28
+ "#{model.class} should not have an error on attribute #{attribute.inspect}"
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ RSpec::Matchers.define :have_module do |mod_or_name|
2
+ match do |obj|
3
+ !!obj.included_modules.detect { |m| m.to_s == mod_or_name.to_s }
4
+ end
5
+
6
+ failure_message_for_should do |obj|
7
+ "expected %p with modules %p to include module '%s'"%[obj, obj.included_modules, mod_or_name]
8
+ end
9
+
10
+ failure_message_for_should_not do |obj|
11
+ "expected %p with modules %p to not include module '%s'"%[obj, obj.included_modules, mod_or_name]
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # http://solnic.eu/2011/01/14/custom-rspec-2-matchers.html
2
+ RSpec::Matchers.define :have_reader do |attribute|
3
+ match do |model|
4
+ model.respond_to?(attribute)
5
+ end
6
+
7
+ failure_message_for_should do |model|
8
+ if @message
9
+ "Validation errors #{model.errors[attribute].inspect} should include #{@message.inspect}"
10
+ else
11
+ "#{model.class} should have attribute reader #{attribute.inspect}"
12
+ end
13
+ end
14
+
15
+ failure_message_for_should_not do |model|
16
+ "#{model.class} should not have attribute reader #{attribute.inspect}"
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # http://solnic.eu/2011/01/14/custom-rspec-2-matchers.html
2
+ RSpec::Matchers.define :have_writer do |attribute|
3
+ match do |model|
4
+ model.respond_to?("#{attribute}=")
5
+ end
6
+
7
+ failure_message_for_should do |model|
8
+ if @message
9
+ "Validation errors #{model.errors[attribute].inspect} should include #{@message.inspect}"
10
+ else
11
+ "#{model.class} should have attribute writer #{attribute.inspect}"
12
+ end
13
+ end
14
+
15
+ failure_message_for_should_not do |model|
16
+ "#{model.class} should not have attribute writer #{attribute.inspect}"
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ RSpec::Matchers.define :have_instance_variable do |var_symbol|
2
+ chain :== do |value|
3
+ @value = value
4
+ end
5
+
6
+ match do |model|
7
+ @ivar = model.instance_variable_get("@#{var_symbol.to_s}")
8
+
9
+ if @value
10
+ @ivar == @value
11
+ else
12
+ @ivar
13
+ end
14
+ end
15
+
16
+ failure_message_for_should do |model|
17
+ if @message
18
+ "#{model.class} should have instance variable #{var_symbol.inspect} == #{value.inspect}"
19
+ else
20
+ "#{model.class} should have instance variable #{var_symbol.inspect}"
21
+ end
22
+ end
23
+
24
+ failure_message_for_should_not do |model|
25
+ if @message
26
+ "#{model.class} should not have instance variable #{var_symbol.inspect} == #{value.inspect}"
27
+ else
28
+ "#{model.class} should not have instance variable #{var_symbol.inspect}"
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ require 'active_support/concern'
2
+
3
+ module SpecHelpers
4
+ module BaseBehaviors
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+
9
+ class ::StatusOkBehavior
10
+ include Decks::Behavior
11
+
12
+ def self.call_with_downstream_app(env, app)
13
+ [200, {'Content-Type' => 'text/plain'}, ["OK"]]
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ # constructs 2 different trees of routing for our examples purposes.
2
+ #
3
+ # + root
4
+ # + child
5
+ # + grandchild
6
+ # + great_grandchild
7
+ #
8
+ # And a more complex version:
9
+ #
10
+ # + root_1
11
+ # + child_1
12
+ # + grandchild_1
13
+ # + grandchild_2
14
+ # + great_grandchild_1
15
+ # + great_grandchild_2
16
+ # + child_2
17
+ # + grandchild_3
18
+ # + great_grandchild_3
19
+ # + root_2
20
+ #
21
+ # This include doesn't take into account any slug information(as they are generated
22
+ # by the Circuit::Node blueprint already). Also, each of these is persisted, so if you want
23
+ # something faster or don't require routing tree, you should consider using a stub or
24
+ # `node_class.make` to generate a non-persisted record.
25
+ #
26
+ require 'active_support/concern'
27
+
28
+ module SpecHelpers
29
+ module BaseModels
30
+ extend ActiveSupport::Concern
31
+
32
+ included do
33
+ let(:node_class) { Circuit::Node }
34
+ let(:site_class) { Circuit::Site }
35
+
36
+ let(:site_1) { site_class.make! :host => "www.foo.com", :aliases => [] }
37
+ let(:root_1) { node_class.make! :slug => nil, :site => site_1 }
38
+ let(:child_1) { node_class.make! :parent => root_1 }
39
+ let(:grandchild_1) { node_class.make! :parent => child_1 }
40
+ let(:grandchild_2) { node_class.make! :parent => child_1 }
41
+ let(:great_grandchild_1) { node_class.make! :parent => grandchild_2 }
42
+ let(:great_grandchild_2) { node_class.make! :parent => grandchild_2 }
43
+ let(:child_2) { node_class.make! :parent => root_1 }
44
+ let(:grandchild_3) { node_class.make! :parent => child_2 }
45
+ let(:great_grandchild_3) { node_class.make! :parent => grandchild_3 }
46
+
47
+ let(:site_2) { site_class.make! :host => "www.bar.com", :aliases => [] }
48
+ let(:root_2) { node_class.make! :slug => nil, :site => site_2 }
49
+
50
+ let(:site) { site_class.make! }
51
+ let(:root) { node_class.make! :slug => nil, :site => site }
52
+ let(:child) { node_class.make! :parent => root }
53
+ let(:grandchild) { node_class.make! :parent => child }
54
+ let(:great_grandchild) { node_class.make! :parent => grandchild }
55
+
56
+ let(:dup_site_1) { site_class.make! :host => "dup1.com", :aliases => [] }
57
+ let(:dup_site_1_dup) { site_class.make! :host => "dup1.com", :aliases => %w[foo.com] }
58
+ let(:dup_site_2) { site_class.make! :host => "dup2.com", :aliases => [] }
59
+ let(:dup_site_2_dup) { site_class.make! :host => "bar.com", :aliases => %w[dup2.com] }
60
+ let(:dup_site_3) { site_class.make! :host => "wow1.com", :aliases => %w[dup3.com] }
61
+ let(:dup_site_3_dup) { site_class.make! :host => "wow2.com", :aliases => %w[dup3.com] }
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/module/delegation'
3
+
4
+ module SpecHelpers
5
+ module LoggerHelpers
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :default_logger, :use_logger
10
+
11
+ around :each do |example|
12
+ @default_logger = Circuit.logger
13
+
14
+ if clean_logger?
15
+ Circuit.logger = nil
16
+ elsif !default_logger?
17
+ @logger_sio = StringIO.new
18
+ Circuit.logger = Logger.new(@logger_sio)
19
+ end
20
+
21
+ example.run
22
+
23
+ if clean_logger?
24
+ clean_logger!(false)
25
+ elsif !default_logger?
26
+ @logger_sio.close
27
+ @logger_sio = nil
28
+ end
29
+
30
+ Circuit.logger = @default_logger
31
+ end
32
+ end
33
+
34
+ def use_logger!(key)
35
+ @use_logger = (key ? key.to_sym : nil)
36
+ end
37
+
38
+ def use_logger?(key)
39
+ @use_logger == key.to_sym
40
+ end
41
+
42
+ def clean_logger!(val=true)
43
+ use_logger!(val ? :clean : false)
44
+ end
45
+ def clean_logger?() use_logger?(:clean); end
46
+
47
+ def default_logger!(val=true)
48
+ use_logger!(val ? :default : false)
49
+ end
50
+ def default_logger?() use_logger?(:default); end
51
+
52
+ def logger_output
53
+ raise "Clean logger used" if clean_logger?
54
+ raise "Default logger used" if default_logger?
55
+ @logger_sio.string
56
+ end
57
+ end
58
+ end