ripple 1.0.0.beta → 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/.gitignore +10 -6
  2. data/Gemfile +6 -15
  3. data/Gemfile.rails30 +3 -0
  4. data/Gemfile.rails31 +3 -0
  5. data/Gemfile.rails32 +3 -0
  6. data/Guardfile +3 -1
  7. data/LICENSE +16 -0
  8. data/README.markdown +173 -0
  9. data/RELEASE_NOTES.textile +286 -0
  10. data/Rakefile +19 -0
  11. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +1 -0
  12. data/lib/rails/generators/ripple/model/model_generator.rb +1 -1
  13. data/lib/rails/generators/ripple/model/templates/{model.rb → model.rb.erb} +0 -0
  14. data/lib/rails/generators/ripple/observer/observer_generator.rb +1 -1
  15. data/lib/rails/generators/ripple/observer/templates/{observer.rb → observer.rb.erb} +0 -2
  16. data/lib/rails/generators/ripple/test/templates/cucumber.rb.erb +7 -0
  17. data/lib/rails/generators/ripple/test/test_generator.rb +17 -13
  18. data/lib/rails/generators/ripple_generator.rb +1 -0
  19. data/lib/ripple/associations.rb +65 -55
  20. data/lib/ripple/associations/embedded.rb +1 -1
  21. data/lib/ripple/associations/linked.rb +1 -1
  22. data/lib/ripple/associations/many.rb +1 -1
  23. data/lib/ripple/associations/many_embedded_proxy.rb +3 -2
  24. data/lib/ripple/associations/many_linked_proxy.rb +1 -1
  25. data/lib/ripple/associations/many_reference_proxy.rb +7 -5
  26. data/lib/ripple/associations/proxy.rb +2 -2
  27. data/lib/ripple/attribute_methods.rb +69 -61
  28. data/lib/ripple/attribute_methods/dirty.rb +2 -2
  29. data/lib/ripple/attribute_methods/read.rb +4 -2
  30. data/lib/ripple/callbacks.rb +23 -26
  31. data/lib/ripple/conflict/basic_resolver.rb +6 -2
  32. data/lib/ripple/conflict/document_hooks.rb +26 -0
  33. data/lib/ripple/conflict/resolver.rb +10 -2
  34. data/lib/ripple/conflict/test_helper.rb +3 -2
  35. data/lib/ripple/conversion.rb +1 -0
  36. data/lib/ripple/core_ext.rb +1 -0
  37. data/lib/ripple/core_ext/casting.rb +2 -0
  38. data/lib/ripple/core_ext/indexes.rb +89 -0
  39. data/lib/ripple/document.rb +23 -22
  40. data/lib/ripple/document/key.rb +12 -14
  41. data/lib/ripple/document/persistence.rb +99 -84
  42. data/lib/ripple/embedded_document.rb +9 -10
  43. data/lib/ripple/embedded_document/persistence.rb +42 -44
  44. data/lib/ripple/i18n.rb +4 -1
  45. data/lib/ripple/indexes.rb +151 -0
  46. data/lib/ripple/locale/en.yml +4 -0
  47. data/lib/ripple/locale/fr.yml +24 -0
  48. data/lib/ripple/nested_attributes.rb +92 -90
  49. data/lib/ripple/properties.rb +2 -1
  50. data/lib/ripple/railtie.rb +9 -0
  51. data/lib/ripple/railties/ripple.rake +32 -15
  52. data/lib/ripple/serialization.rb +50 -52
  53. data/lib/ripple/test_server.rb +1 -2
  54. data/lib/ripple/timestamps.rb +6 -8
  55. data/lib/ripple/validations.rb +19 -21
  56. data/lib/ripple/version.rb +1 -1
  57. data/ripple.gemspec +6 -5
  58. data/spec/generators/ripple/configuration_generator_spec.rb +9 -0
  59. data/spec/generators/ripple/js_generator_spec.rb +14 -0
  60. data/spec/generators/ripple/model_generator_spec.rb +64 -0
  61. data/spec/generators/ripple/observer_generator_spec.rb +20 -0
  62. data/spec/generators/ripple/test_generator_spec.rb +116 -0
  63. data/spec/generators/ripple_generator_spec.rb +11 -0
  64. data/spec/integration/ripple/conflict_resolution_spec.rb +35 -4
  65. data/spec/integration/ripple/indexes_spec.rb +47 -0
  66. data/spec/ripple/associations/many_embedded_proxy_spec.rb +50 -60
  67. data/spec/ripple/associations/many_linked_proxy_spec.rb +2 -2
  68. data/spec/ripple/associations/many_reference_proxy_spec.rb +1 -1
  69. data/spec/ripple/associations_spec.rb +16 -7
  70. data/spec/ripple/attribute_methods_spec.rb +43 -2
  71. data/spec/ripple/callbacks_spec.rb +120 -101
  72. data/spec/ripple/conversion_spec.rb +5 -13
  73. data/spec/ripple/core_ext_spec.rb +93 -15
  74. data/spec/ripple/finders_spec.rb +0 -2
  75. data/spec/ripple/indexes_spec.rb +111 -0
  76. data/spec/ripple/observable_spec.rb +1 -2
  77. data/spec/ripple/persistence_spec.rb +55 -32
  78. data/spec/ripple/properties_spec.rb +1 -1
  79. data/spec/ripple/ripple_spec.rb +5 -5
  80. data/spec/ripple/timestamps_spec.rb +9 -2
  81. data/spec/ripple/validations_spec.rb +50 -52
  82. data/spec/spec_helper.rb +9 -2
  83. data/spec/support/generator_setup.rb +26 -0
  84. data/spec/support/models.rb +1 -0
  85. data/spec/support/models/box.rb +1 -0
  86. data/spec/support/models/clock.rb +1 -1
  87. data/spec/support/models/indexer.rb +26 -0
  88. data/spec/support/models/post.rb +3 -2
  89. data/spec/support/models/widget.rb +2 -0
  90. data/spec/support/search.rb +2 -2
  91. data/spec/support/test_server.rb +23 -11
  92. data/spec/support/test_server.yml.example +1 -1
  93. metadata +159 -135
  94. data/spec/support/mocks.rb +0 -4
@@ -37,7 +37,8 @@ module Ripple
37
37
  # @param [String, Symbol] key the key of the property
38
38
  # @param [Class] type the Ruby type of the property. Use {Boolean} for true or false types.
39
39
  # @param [Hash] options configuration options
40
- # @option options [Object, Proc] :default (nil) a default value for the property, or a lambda to evaluate when providing the default.
40
+ # @option options [Object, Proc] :default (nil) a default value
41
+ # for the property, or a lambda to evaluate when providing the default.
41
42
  def initialize(key, type, options={})
42
43
  @options = options.to_options
43
44
  @key = key.to_sym
@@ -13,5 +13,14 @@ module Ripple
13
13
  Ripple.load_configuration Rails.root.join('config', 'ripple.yml'), [Rails.env]
14
14
  end
15
15
  end
16
+
17
+ initializer "ripple.configure_test_server_root", :after => "ripple.configure_rails_initialization" do
18
+ unless Rails.env.development? || Rails.env.production?
19
+ # Make sure the TestServer lives in the default location, if
20
+ # not set in the config file.
21
+ Ripple.config[:root] ||= (Rails.root + 'tmp/riak_test_server').to_s
22
+ Ripple.config[:js_source_dir] ||= (Rails.root + "app/mapreduce").to_s
23
+ end
24
+ end
16
25
  end
17
26
  end
@@ -22,14 +22,8 @@ namespace :riak do
22
22
  cluster.create
23
23
  end
24
24
 
25
- desc "Destroys and recreates the cluster for the current environment."
26
- task :reset => ['riak:destroy', 'riak:setup']
27
-
28
- desc "Creates the Riak cluster and loads the seed data."
29
- task :setup => ["riak:create", "db:seed"]
30
-
31
25
  desc "Destroys the generated Riak cluster for the current environment."
32
- task :destroy => :rails_env do
26
+ task :destroy => ['rails_env', 'riak:stop'] do
33
27
  cluster.destroy
34
28
  end
35
29
 
@@ -60,13 +54,36 @@ namespace :riak do
60
54
  end
61
55
 
62
56
  namespace :db do
57
+ desc "Creates the database(s) for the current environment"
63
58
  task :create => "riak:create"
64
- namespace(:create){ task :all => "riak:create:all" }
65
- task :drop => "riak:drop"
66
- namespace(:drop) { task :all => "riak:drop:all" }
67
- task :setup => "riak:setup"
68
- task :reset => "riak:reset"
69
- task seed: ['riak:start', 'environment'] do
59
+
60
+ namespace(:create) do
61
+ desc "Creates the database(s) for all environments"
62
+ task :all => "riak:create:all"
63
+ end
64
+
65
+ desc "Drops the database(s) for the current environment"
66
+ task :drop => ['db:stop', 'riak:drop']
67
+
68
+ namespace(:drop) do
69
+ desc "Drops the database(s) for all environments"
70
+ task :all => "riak:drop:all"
71
+ end
72
+
73
+ desc "Starts the database(s) for the current environment"
74
+ task :start => 'riak:start'
75
+
76
+ desc "Stops the database(s) for the current environment"
77
+ task :stop => 'riak:stop'
78
+
79
+ desc "Creates the database(s) and loads the seed data."
80
+ task :setup => ['db:create', 'db:start', 'db:seed']
81
+
82
+ desc "Drops and recreates the database(s) for the current environment."
83
+ task :reset => ['db:drop', 'db:setup']
84
+
85
+ desc "Loads the seed data in to the current environment"
86
+ task :seed => :environment do
70
87
  Rails.application.load_seed
71
88
  end
72
89
  end
@@ -79,8 +96,8 @@ end
79
96
 
80
97
  def cluster(environment=nil, config=nil)
81
98
  environment ||= Rails.env
82
- config ||= load_config[environment]
99
+ config ||= load_config[environment].with_indifferent_access
83
100
  root = Rails.root + "db" + environment.to_s
84
101
  # TODO: We need to deal with multiple hosts and client ports
85
- Riak::Cluster.new(config.merge(:root => root.to_s).with_indifferent_access)
102
+ Riak::Cluster.new({ :root => root.to_s }.merge(config).with_indifferent_access)
86
103
  end
@@ -24,61 +24,59 @@ module Ripple
24
24
  extend ActiveSupport::Concern
25
25
  include ::ActiveModel::Serializers::JSON
26
26
 
27
- module InstanceMethods
28
- # Creates a Hash suitable for conversion to an external format.
29
- # @param [Hash] options (nil) serialization options
30
- # @option options [Array<Symbol>] :only emit only the specified attributes
31
- # @option options [Array<Symbol>] :except omit the specified attributes
32
- # @option options [Array<Symbol>, Hash] :include include the
33
- # specified associations (with or without extra
34
- # options). This defaults to all embedded associations.
35
- # @return [Hash] a hash of attributes and embedded documents
36
- def serializable_hash(options=nil)
37
- options = options.try(:clone) || {}
38
-
39
- unless options.has_key?(:include)
40
- options[:include] = self.class.embedded_associations.map(&:name)
41
- end
42
-
43
- hash = super(options)
44
-
45
- hash['key'] = key if respond_to?(:key) && key.present? && (!options[:except] || !options[:except].map(&:to_s).include?("key"))
46
-
47
- serializable_add_includes(options) do |association, records, opts|
48
- hash[association.to_s] = records.is_a?(Enumerable) ? records.map {|r| r.serializable_hash(opts) } : records.serializable_hash(opts)
49
- end
50
- hash
27
+ # Creates a Hash suitable for conversion to an external format.
28
+ # @param [Hash] options (nil) serialization options
29
+ # @option options [Array<Symbol>] :only emit only the specified attributes
30
+ # @option options [Array<Symbol>] :except omit the specified attributes
31
+ # @option options [Array<Symbol>, Hash] :include include the
32
+ # specified associations (with or without extra
33
+ # options). This defaults to all embedded associations.
34
+ # @return [Hash] a hash of attributes and embedded documents
35
+ def serializable_hash(options=nil)
36
+ options = options.try(:clone) || {}
37
+
38
+ unless options.has_key?(:include)
39
+ options[:include] = self.class.embedded_associations.map(&:name)
51
40
  end
52
-
53
- private
54
- def serializable_add_includes(options={})
55
- return unless include_associations = options.delete(:include)
56
-
57
- base_only_or_except = {
58
- :except => options[:except],
59
- :only => options[:only]
60
- }
61
-
62
- include_has_options = include_associations.is_a?(Hash)
63
- associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
64
-
65
- for association in associations
66
- records = case self.class.associations[association.to_sym].type
67
- when :many
68
- send(association).to_a
69
- when :one
70
- send(association)
71
- end
72
-
73
- unless records.nil?
74
- association_options = include_has_options ? include_associations[association] : base_only_or_except
75
- opts = options.merge(association_options)
76
- yield(association, records, opts)
77
- end
41
+
42
+ hash = super(options)
43
+
44
+ hash['key'] = key if respond_to?(:key) && key.present? && (!options[:except] || !options[:except].map(&:to_s).include?("key"))
45
+
46
+ serializable_add_includes(options) do |association, records, opts|
47
+ hash[association.to_s] = records.is_a?(Enumerable) ? records.map {|r| r.serializable_hash(opts) } : records.serializable_hash(opts)
48
+ end
49
+ hash
50
+ end
51
+
52
+ private
53
+ def serializable_add_includes(options={})
54
+ return unless include_associations = options.delete(:include)
55
+
56
+ base_only_or_except = {
57
+ :except => options[:except],
58
+ :only => options[:only]
59
+ }
60
+
61
+ include_has_options = include_associations.is_a?(Hash)
62
+ associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
63
+
64
+ for association in associations
65
+ records = case self.class.associations[association.to_sym].type
66
+ when :many
67
+ send(association).to_a
68
+ when :one
69
+ send(association)
70
+ end
71
+
72
+ unless records.nil?
73
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
74
+ opts = options.merge(association_options)
75
+ yield(association, records, opts)
78
76
  end
79
-
80
- options[:include] = include_associations
81
77
  end
78
+
79
+ options[:include] = include_associations
82
80
  end
83
81
  end
84
82
  end
@@ -23,13 +23,12 @@ module Ripple
23
23
  def initialize(options=Ripple.config.dup)
24
24
  options[:env] ||= {}
25
25
  options[:env][:riak_kv] ||= {}
26
- options[:env][:riak_kv][:js_source_dir] ||= Ripple.config.delete(:js_source_dir) || (Rails.root + "app/mapreduce").to_s
26
+ options[:env][:riak_kv][:js_source_dir] ||= Ripple.config.delete(:js_source_dir)
27
27
  options[:env][:riak_kv][:map_cache_size] ||= 0
28
28
  options[:env][:riak_core] ||= {}
29
29
  options[:env][:riak_core][:http] ||= [ Tuple[Ripple.config[:host], Ripple.config[:http_port]] ]
30
30
  options[:env][:riak_kv][:pb_port] ||= Ripple.config[:pb_port]
31
31
  options[:env][:riak_kv][:pb_ip] ||= Ripple.config[:host]
32
- options[:root] ||= (Rails.root + 'tmp/riak_test_server').to_s
33
32
  super(options)
34
33
  end
35
34
  end
@@ -10,18 +10,16 @@ module Ripple
10
10
  module ClassMethods
11
11
  # Adds the :created_at and :updated_at timestamp properties to
12
12
  # the document.
13
- def timestamps!
14
- property :created_at, Time, :default => proc { Time.now }
15
- property :updated_at, Time
13
+ def timestamps!(options={})
14
+ property :created_at, Time, options.merge(:default => proc { Time.now })
15
+ property :updated_at, Time, options.dup
16
16
  before_save :touch
17
17
  end
18
18
  end
19
19
 
20
- module InstanceMethods
21
- # Sets the :updated_at attribute before saving the document.
22
- def touch
23
- self.updated_at = Time.now
24
- end
20
+ # Sets the :updated_at attribute before saving the document.
21
+ def touch
22
+ self.updated_at = Time.now
25
23
  end
26
24
  end
27
25
  end
@@ -36,31 +36,29 @@ module Ripple
36
36
 
37
37
  # Instantiates a new document, applies attributes from a block, and saves it
38
38
  # Raises Ripple::DocumentInvalid if the record did not save
39
- def create!(attrs={}, &block)
40
- obj = create(attrs, &block)
39
+ def create!(*args, &block)
40
+ obj = create(*args, &block)
41
41
  (raise Ripple::DocumentInvalid.new(obj) if obj.new?) || obj
42
42
  end
43
43
  end
44
44
 
45
- module InstanceMethods
46
- # @private
47
- def save(options={:validate => true})
48
- return false if options[:validate] && !valid?
49
- super()
50
- end
51
-
52
- # Saves the document and raises {DocumentInvalid} exception if
53
- # validations fail.
54
- def save!
55
- (raise Ripple::DocumentInvalid.new(self) unless save) || true
56
- end
57
-
58
- # Sets the passed attributes and saves the document, raising a
59
- # {DocumentInvalid} exception if the validations fail.
60
- def update_attributes!(attrs)
61
- self.attributes = attrs
62
- save!
63
- end
45
+ # @private
46
+ def save(options={:validate => true})
47
+ return false if options[:validate] && !valid?
48
+ super()
49
+ end
50
+
51
+ # Saves the document and raises {DocumentInvalid} exception if
52
+ # validations fail.
53
+ def save!
54
+ (raise Ripple::DocumentInvalid.new(self) unless save) || true
55
+ end
56
+
57
+ # Sets the passed attributes and saves the document, raising a
58
+ # {DocumentInvalid} exception if the validations fail.
59
+ def update_attributes!(attrs)
60
+ self.attributes = attrs
61
+ save!
64
62
  end
65
63
  end
66
64
  end
@@ -1,3 +1,3 @@
1
1
  module Ripple
2
- VERSION = "1.0.0.beta"
2
+ VERSION = "1.0.0.beta2"
3
3
  end
data/ripple.gemspec CHANGED
@@ -12,11 +12,12 @@ Gem::Specification.new do |gem|
12
12
  gem.authors = ["Sean Cribbs"]
13
13
 
14
14
  # Deps
15
- gem.add_development_dependency "rspec", "~>2.6.0"
16
- gem.add_development_dependency 'rake', '~> 0.8.7'
17
- gem.add_dependency "riak-client", "~>#{Ripple::VERSION}"
18
- gem.add_dependency "activesupport", [">= 3.0.0", "< 3.2.0"]
19
- gem.add_dependency "activemodel", [">= 3.0.0", "< 3.2.0"]
15
+ gem.add_development_dependency "rspec", "~>2.8.0"
16
+ gem.add_development_dependency 'rake'
17
+ gem.add_development_dependency 'ammeter', '~>0.2.2'
18
+ gem.add_dependency "riak-client", "~> 1.0.0"
19
+ gem.add_dependency "activesupport", [">= 3.0.0", "< 3.3.0"]
20
+ gem.add_dependency "activemodel", [">= 3.0.0", "< 3.3.0"]
20
21
  gem.add_dependency "tzinfo"
21
22
 
22
23
  # Files
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require 'rails/generators/ripple/configuration/configuration_generator'
3
+
4
+ describe Ripple::Generators::ConfigurationGenerator do
5
+ before { run_generator }
6
+ it "should generate the ripple.yml file" do
7
+ file('config/ripple.yml').should exist
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'rails/generators/ripple/js/js_generator'
3
+
4
+ describe Ripple::Generators::JsGenerator do
5
+ before { run_generator }
6
+
7
+ it "should create an app/mapreduce directory" do
8
+ file('app/mapreduce').should exist
9
+ end
10
+
11
+ it "should copy all standard JS files into the mapreduce directory" do
12
+ Dir[file('app/mapreduce/*')].sort.map{|f| File.basename(f) }.should == %w{contrib.js iso8601.js ripple.js}
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ require 'rails/generators/ripple/model/model_generator'
3
+
4
+ shared_examples_for :model_generator do
5
+ it("should create the model file"){ model_file.should exist }
6
+ it { should contain(class_decl) }
7
+ it("should create the attribute declarations") do
8
+ attributes.each do |name, type|
9
+ should contain("property :#{name}, #{type}")
10
+ end
11
+ end
12
+ end
13
+
14
+ shared_examples_for :subclass_model_generator do
15
+ it_behaves_like :model_generator
16
+ it { should_not contain("include Ripple::Document") }
17
+ it { should_not contain("include Ripple::EmbeddedDocument") }
18
+ end
19
+
20
+ shared_examples_for :embedded_document_generator do
21
+ it_behaves_like :model_generator
22
+ it { should contain("include Ripple::EmbeddedDocument") }
23
+ end
24
+
25
+ shared_examples_for :document_generator do
26
+ it_behaves_like :model_generator
27
+ it { should contain("include Ripple::Document") }
28
+ end
29
+
30
+ describe Ripple::Generators::ModelGenerator do
31
+ let(:cli){ %w{general_model} }
32
+ let(:model_file){ file('app/models/general_model.rb') }
33
+ let(:class_decl){ "class GeneralModel" }
34
+ let(:attributes){ {} }
35
+ subject { model_file }
36
+ before { run_generator cli }
37
+
38
+ describe "generating a bare model" do
39
+ it_behaves_like :document_generator
40
+ end
41
+
42
+ describe "generating with attributes" do
43
+ let(:cli){ %w{general_model name:string shipped:datetime size:integer} }
44
+ let(:attributes) { {:name => String, :shipped => Time, :size => Integer } }
45
+ it_behaves_like :document_generator
46
+ end
47
+
48
+ describe "generating a model with a parent class" do
49
+ let(:cli){ %w{general_model --parent=widget} }
50
+ let(:class_decl){ "class GeneralModel < Widget" }
51
+ it_behaves_like :subclass_model_generator
52
+ end
53
+
54
+ describe "generating an embedded model" do
55
+ let(:cli){ %w{general_model --embedded} }
56
+ it_behaves_like :embedded_document_generator
57
+ end
58
+
59
+ describe "generating a model embedded in a parent document" do
60
+ let(:cli){ %w{general_model --embedded-in=widget} }
61
+ it_behaves_like :embedded_document_generator
62
+ it { should contain("embedded_in :widget") }
63
+ end
64
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'rails/generators/ripple/observer/observer_generator'
3
+
4
+ describe Ripple::Generators::ObserverGenerator do
5
+ context "in the top-level scope" do
6
+ before { run_generator %w{person} }
7
+ subject{ file('app/models/person_observer.rb') }
8
+
9
+ it { should exist }
10
+ it { should contain("class PersonObserver < ActiveModel::Observer") }
11
+ end
12
+
13
+ context "in a nested scope" do
14
+ before { run_generator %w{profiles/social} }
15
+ subject { file('app/models/profiles/social_observer.rb') }
16
+
17
+ it { should exist }
18
+ it { should contain("class Profiles::SocialObserver < ActiveModel::Observer") }
19
+ end
20
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'rails/generators/ripple/test/test_generator'
3
+
4
+ describe Ripple::Generators::TestGenerator do
5
+ context "when Cucumber is present" do
6
+ before { mkdir_p file('features/support') }
7
+ before { run_generator }
8
+
9
+ it "should create a support file for the test server" do
10
+ file('features/support/ripple.rb').should exist
11
+ end
12
+ end
13
+
14
+ context "when RSpec is present" do
15
+ let(:original_contents) do
16
+ [
17
+ "require 'rspec'",
18
+ "RSpec.configure do |config|",
19
+ " config.mock_with :rspec",
20
+ "end"
21
+ ]
22
+ end
23
+ let(:helper) { file('spec/spec_helper.rb') }
24
+ let(:contents) { File.read(helper) }
25
+ before do
26
+ mkdir_p file('spec')
27
+ File.open(helper,'w') do |f|
28
+ f.write original_contents.join("\n")
29
+ end
30
+ run_generator
31
+ end
32
+
33
+ it "should insert the test server require" do
34
+ contents.should include("require 'ripple/test_server'")
35
+ end
36
+
37
+ it "should insert the test server setup" do
38
+ contents.should include(" config.before(:suite) { Ripple::TestServer.setup }")
39
+ contents.should include(" config.after(:each) { Ripple::TestServer.clear }")
40
+ end
41
+
42
+ context "when the configuration block is indented" do
43
+ let(:original_contents) do
44
+ [
45
+ "require 'rspec'",
46
+ "require 'spork'",
47
+ "Spork.prefork do",
48
+ " RSpec.configure do |config|",
49
+ " config.mock_with :rspec",
50
+ " end",
51
+ "end"
52
+ ]
53
+ end
54
+
55
+ it "should insert the test server require with additional indentation" do
56
+ contents.should include(" require 'ripple/test_server'")
57
+ end
58
+
59
+ it "should insert the test server setup with additional indentation" do
60
+ contents.should include(" config.before(:suite) { Ripple::TestServer.setup }")
61
+ contents.should include(" config.after(:each) { Ripple::TestServer.clear }")
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when Test::Unit is present" do
67
+ let(:original_contents) do
68
+ [
69
+ "require 'active_support/test_case'",
70
+ "class ActiveSupport::TestCase",
71
+ " setup :load_fixtures",
72
+ "end"
73
+ ]
74
+ end
75
+ let(:helper) { file('test/test_helper.rb') }
76
+ let(:contents) { File.read(helper) }
77
+ before do
78
+ mkdir_p file('test')
79
+ File.open(helper,'w') do |f|
80
+ f.write original_contents.join("\n")
81
+ end
82
+ run_generator
83
+ end
84
+
85
+ it "should insert the test server require" do
86
+ contents.should include("require 'ripple/test_server'")
87
+ end
88
+
89
+ it "should insert the test server setup and teardown" do
90
+ contents.should include(" setup { Ripple::TestServer.setup }")
91
+ contents.should include(" teardown { Ripple::TestServer.clear }")
92
+ end
93
+
94
+ context "when the test case class is indented" do
95
+ let(:original_contents) do
96
+ [
97
+ "require 'active_support/test_case'",
98
+ "module MyApp",
99
+ " class ActiveSupport::TestCase",
100
+ " setup :load_fixtures",
101
+ " end",
102
+ "end"
103
+ ]
104
+ end
105
+
106
+ it "should insert the test server require with additional indentation" do
107
+ contents.should include(" require 'ripple/test_server'")
108
+ end
109
+
110
+ it "should insert the test server setup and teardown with additional indentation" do
111
+ contents.should include(" setup { Ripple::TestServer.setup }")
112
+ contents.should include(" teardown { Ripple::TestServer.clear }")
113
+ end
114
+ end
115
+ end
116
+ end