From caa9bd3aa2477c5f277f32c9f24b2e12000c71ab Mon Sep 17 00:00:00 2001 From: "Michael S. Klishin" Date: Sun, 4 May 2008 15:31:10 +0300 Subject: [PATCH 1/3] Add Rake task that detects spec groups intereference --- Rakefile | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/Rakefile b/Rakefile index dc43f47c..76bd7e03 100644 --- a/Rakefile +++ b/Rakefile @@ -6,7 +6,7 @@ require 'strokedb'; require 'core_ext' require 'task/echoe' Echoe.taskify do Dir['task/**/*.task'].each {|t| load t} - + namespace :echoe do Echoe.new('strokedb', StrokeDB::VERSION) do |g| g.author = ['Yurii Rashkovskii', 'Oleg Andreev'] @@ -19,15 +19,15 @@ Echoe.taskify do time), it scales infinitely, it even allows free versioning and integrates perfectly with Ruby applications. EOF - + g.platform = Gem::Platform::RUBY g.dependencies = ['diff-lcs >= 1.1.2', 'uuidtools >= 1.0.3', 'json >= 1.1.2'] - + g.manifest_name = 'meta/MANIFEST' g.ignore_pattern = /(^\.git|^.DS_Store$|^meta|^test\/storages|^examples\/(.*).strokedb|^bugs)/ g.executable_pattern = 'bin/strokedb' end - + desc 'tests packaged files to ensure they are all present' task :verify => :package do # An error message will be displayed if files are missing @@ -35,14 +35,14 @@ Echoe.taskify do puts "\nThe library files are present" end end - + desc 'Clean tree, update manifest, and install gem' task :magic => [:clean, :manifest, :install] end - + desc 'Check what\'s up in this mug' task :sup => [:'rcov:run', :'rcov:verify'] - + # Developers: Run this before commiting! desc 'Check everything over before commiting!' task :aok => [:'rcov:verbose', :'rcov:strict', :'rcov:open', @@ -57,4 +57,29 @@ task :cruise => [:'ditz:html', :'rdoc:html', :'rcov:bw', :'rcov:verify'] task :default => :list task :list do system 'rake -T' -end \ No newline at end of file +end + + +desc "Detects interfering spec group pairs. By Michael Klishin." +task :interfers do +file = ENV['SPECFILE'] + + all_specs = Dir.glob(File.dirname(__FILE__) + "/spec/**/*_spec.rb") - [File.expand_path(file)] + all_specs.each do |specfile| + pair = "#{specfile} #{file}" + output = `spec -c #{pair}` + + if output =~ /0\sfailures/ + print "." + STDOUT.flush + else + puts "\n\nACHTUNG! Coupled spec groups detected! Fuck! Shit! You should have this fixed ASAP! AAAAA!!!" + puts "spec -c #{pair}" + puts "Run says \n\n" + puts output + end + end + + puts + puts +end From bea81c924e31137463036eb872d7b1b58f427aff Mon Sep 17 00:00:00 2001 From: Yurii Rashkovskii Date: Sun, 4 May 2008 15:33:27 +0300 Subject: [PATCH 2/3] Module.clear_nsurls => Module.reset_nsurls --- lib/strokedb/nsurl.rb | 7 ++++--- spec/lib/strokedb/nsurl_spec.rb | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/strokedb/nsurl.rb b/lib/strokedb/nsurl.rb index a60a32bc..0c9cae1f 100644 --- a/lib/strokedb/nsurl.rb +++ b/lib/strokedb/nsurl.rb @@ -1,7 +1,9 @@ Module.module_eval do - def self.clear_nsurls + def self.reset_nsurls @@nsurls = {} + ::Module.nsurl '' + ::StrokeDB.nsurl StrokeDB::STROKEDB_NSURL end def self.find_by_nsurl(url) @@nsurls[url] @@ -19,5 +21,4 @@ def nsurl(url = nil) end -Module.nsurl '' -StrokeDB.nsurl StrokeDB::STROKEDB_NSURL \ No newline at end of file +Module.reset_nsurls \ No newline at end of file diff --git a/spec/lib/strokedb/nsurl_spec.rb b/spec/lib/strokedb/nsurl_spec.rb index 48472905..8d3a968c 100644 --- a/spec/lib/strokedb/nsurl_spec.rb +++ b/spec/lib/strokedb/nsurl_spec.rb @@ -4,7 +4,11 @@ before(:each) do @module = Module.new - Module.clear_nsurls + Module.reset_nsurls + end + + after(:each) do + Module.reset_nsurls end it "should have nil nsurl by default" do @@ -38,9 +42,14 @@ before(:each) do - Module.clear_nsurls + Module.reset_nsurls end + after(:each) do + Module.reset_nsurls + end + + it "should have empty nsurl by default" do Module.nsurl.should be_empty end @@ -50,7 +59,11 @@ describe StrokeDB do before(:each) do - Module.clear_nsurls + Module.reset_nsurls + end + + after(:each) do + Module.reset_nsurls end it "should have #{STROKEDB_NSURL} nsurl by default" do From b8eaa6788d65d7a2e7a86233354324b695f368ae Mon Sep 17 00:00:00 2001 From: "Michael S. Klishin" Date: Sun, 4 May 2008 15:34:47 +0300 Subject: [PATCH 3/3] Document.collect_meta_modules has been reworked (not yet perfect though) --- lib/strokedb/document.rb | 111 +++++++++++++------- lib/strokedb/document/meta.rb | 2 + spec/lib/strokedb/document/document_spec.rb | 14 +-- 3 files changed, 80 insertions(+), 47 deletions(-) diff --git a/lib/strokedb/document.rb b/lib/strokedb/document.rb index 06d5cfd0..d7b7f250 100644 --- a/lib/strokedb/document.rb +++ b/lib/strokedb/document.rb @@ -36,7 +36,7 @@ def inspect end # - # Raised when Document#save! is called on an invalid document + # Raised when Document#save! is called on an invalid document # (for which doc.valid? returns false) # class InvalidDocumentError < StandardError #:nodoc: @@ -104,7 +104,7 @@ def initialize(document) def <<(meta) add_meta(meta, :call_initialization_callbacks => true) end - + alias :_delete :delete def delete(meta) case meta @@ -117,13 +117,13 @@ def delete(meta) else raise ArgumentError, "Meta should be either document or meta module" end - + @document[:meta] = self - + if _module @document.unextend(_module) end - + end def add_meta(meta, opts = {}) @@ -148,7 +148,7 @@ def add_meta(meta, opts = {}) if _module @document.extend(_module) - if opts['call_initialization_callbacks'] + if opts['call_initialization_callbacks'] @document.send!(:execute_callbacks_for, _module, :on_initialization) @document.send!(:execute_callbacks_for, _module, :on_new_document) if @document.new? end @@ -442,7 +442,7 @@ def update_slots!(hash) update_slots(hash).save! end - + # Updates nil/false slots with a specified hash and returns itself. # Already set slots are not modified (||= is used). # Acts like hash1.reverse_merge(hash2) (hash2.merge(hash1)). @@ -621,14 +621,14 @@ def execute_callbacks_for(origin, name, *args) #:nodoc: end end - # initialize the document. initialize_raw is true when + # initialize the document. initialize_raw is true when # document is initialized from a raw serialized form def do_initialize(store, slots={}, initialize_raw = false) #:nodoc: @callbacks = {} @store = store if initialize_raw - initialize_raw_slots slots + initialize_raw_slots slots @saved = true else @new = true @@ -644,7 +644,7 @@ def initialize_slots(slots) #:nodoc: @slots = {} slots = slots.stringify_keys - # there is a reason for meta slot is initialized separately — + # there is a reason for meta slot is initialized separately — # we need to setup coercions before initializing actual slots if meta = slots['meta'] meta = [meta] unless meta.is_a?(Array) @@ -670,37 +670,72 @@ def initialize_raw_slots(slots) #:nodoc: end end - # returns an array of meta modules (as constants) for a given something - # (a document reference, a document itself, or an array of the former) - def self.collect_meta_modules(store, meta) #:nodoc: - meta_names = [] - - case meta - when VERSIONREF - if m = store.find($1, $2) - mod = Module.find_by_nsurl(m[:nsurl]) - mod = nil if mod == Module - if (mod.nil? && Object.constants.include?(m[:name])) || (mod && mod.constants.include?(m[:name])) - meta_names << (mod ? mod.name : "") + "::" + m[:name] + + class MetaModulesCollector + def initialize(store, subject) + @store = store + @subject = subject + end + + def resolve_module_name(uuid) + if metadoc = @store.find(uuid, self.lookup_version_for_meta(@subject)) + mod = Module.find_by_nsurl(metadoc[:nsurl]) + + if self.has_defined_constant_for_meta?(mod, metadoc) + at_top_level?(mod) ? "::#{metadoc[:name]}" : "#{mod.name}::#{metadoc[:name]}" else - meta_names << Meta.resolve_uuid_name(m[:nsurl],m[:name]) + Meta.resolve_uuid_name(metadoc[:nsurl], metadoc[:name]) end end - when DOCREF - if m = store.find($1) - mod = Module.find_by_nsurl(m[:nsurl]) - mod = nil if mod == Module - if (mod.nil? && Object.constants.include?(m[:name])) || (mod && mod.constants.include?(m[:name])) - meta_names << (mod ? mod.name : "") + "::" + m[:name] - else - meta_names << Meta.resolve_uuid_name(m[:nsurl],m[:name]) - end + end + + def at_top_level?(mod) + mod == Module || mod.nil? + end + + def collect! + meta_names = [] + + case @subject + when VERSIONREF, DOCREF + meta_names << resolve_module_name($1) + when Array + meta_names = @subject.map { |subj| subj = MetaModulesCollector.new(@store, subj).collect! }.flatten + when Document + meta_names << @subject[:name] end - when Array - meta_names = meta.map { |m| collect_meta_modules(store, m) }.flatten - when Document - meta_names << meta[:name] + + meta_names + end + + def lookup_version_for_meta(meta) + version = case meta + when VERSIONREF then $2 + else nil + end + version + end + + def has_defined_constant_for_meta?(mod, metadoc) + top_level_meta?(mod, metadoc) || has_meta_definition?(mod, metadoc) + end + + def top_level_meta?(mod, doc) + (mod == Module && Object.constants.include?(doc[:name])) + end + + def has_meta_definition?(mod, metadoc) + (mod && mod.constants.include?(metadoc[:name])) end + end + + + + # returns an array of meta modules (as constants) for a given something + # (a document reference, a document itself, or an array of the former) + def self.collect_meta_modules(store, meta) #:nodoc: + @collector = MetaModulesCollector.new(store, meta) + meta_names = @collector.collect! meta_names.map { |m| m.is_a?(String) ? (m.constantize rescue nil) : m }.compact end @@ -745,9 +780,9 @@ def mutable? def save! self end - + def make_mutable! unextend(ImmutableDocument) end end -end \ No newline at end of file +end diff --git a/lib/strokedb/document/meta.rb b/lib/strokedb/document/meta.rb index 639ee7b6..2268a563 100644 --- a/lib/strokedb/document/meta.rb +++ b/lib/strokedb/document/meta.rb @@ -252,6 +252,8 @@ def document(store=nil) metadocs.size > 1 ? metadocs.inject { |a, b| a + b }.make_immutable! : metadocs.first end + + def extended(obj) setup_callbacks(obj) if obj.is_a?(Document) end diff --git a/spec/lib/strokedb/document/document_spec.rb b/spec/lib/strokedb/document/document_spec.rb index 578e5f9d..d0c8ea6a 100644 --- a/spec/lib/strokedb/document/document_spec.rb +++ b/spec/lib/strokedb/document/document_spec.rb @@ -885,23 +885,19 @@ def slot1=(v) before(:each) do @store = setup_default_store - @meta = Document.create!(:name => 'SomeDocument') - @document = Document.new(@store,:slot1 => "val1", :slot2 => "val2", :meta => @meta) + Object.send!(:remove_const,'SomeDocument') if defined?(SomeDocument) + SomeDocument = Meta.new + @document = SomeDocument.new(@store,:slot1 => "val1", :slot2 => "val2") @json = @document.to_raw.to_json @decoded_json = JSON.parse(@json) end it "should load meta's module if it is available" do - Object.send!(:remove_const,'SomeDocument') if defined?(SomeDocument) - SomeDocument = Module.new - doc = Document.from_raw(@store,@decoded_json) doc.should be_a_kind_of(SomeDocument) end it "should not load meta's module if it is not available" do - Object.send!(:remove_const,'SomeDocument') if defined?(SomeDocument) - lambda do doc = Document.from_raw(@store,@decoded_json) end.should_not raise_error @@ -916,9 +912,9 @@ def slot1=(v) @store = setup_default_store @metas = [] 3.times do |i| - @metas << Document.create!(@store, :name => "SomeDocument#{i}") + @metas << Meta.new(:name => "SomeDocument#{i}") end - @document = Document.new(@store,:slot1 => "val1", :slot2 => "val2", :meta => @metas) + @document = @metas.inject{|a,b| a+=b}.new(@store,:slot1 => "val1", :slot2 => "val2", :meta => @metas) @json = @document.to_raw.to_json @decoded_json = JSON.parse(@json) end