reactive-dev 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.
@@ -0,0 +1,49 @@
1
+ # Yeah, this is a monkey patch...
2
+ module RubiGen # :nodoc:all
3
+ =begin
4
+ class PathReallyFilteredSource < PathFilteredSource
5
+ def filter_str(filters)
6
+ @filters = filters.first.is_a?(Array) ? filters.first : filters
7
+ return "" if @filters.blank?
8
+ filter_str = @filters.map {|filter| "#{filter}_"}.join(",")
9
+ # filter_str += "," <--- This is exactly what i don't want, because it traps the 'generators' dir at the root of the rubigen gem.
10
+ "{#{filter_str}}"
11
+ end
12
+ end
13
+ =end
14
+ class Base
15
+ # Use reactive gem plugins generators (test_unit, etc).
16
+ # 1. Current application. Use Reactive.dir_for(:generators).
17
+ # 2. User home directory. Search ~/.rubigen/generators.
18
+ # 3. GemPlugins. Search for loaded gems containing /{scope}_generators folder.
19
+ def self.use_plugin_sources!(*filters)
20
+ reset_sources
21
+ new_sources = []
22
+ new_sources << Reactive.dirs_for(:generators).collect{|dir| PathSource.new(:app, dir) } if Reactive.respond_to? :dirs_for
23
+ new_sources << PathFilteredSource.new(:user, "#{Dir.user_home}/.rubigen/", *filters)
24
+ new_sources << Reactive.configuration.gems.map(&:loaded_spec).compact.collect{|spec| RubiGen::PathFilteredSource.new(:GemPlugins, spec.full_gem_path, *filters) }
25
+ write_inheritable_attribute(:sources, new_sources.flatten)
26
+ end
27
+
28
+ def klass
29
+ self.class
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ module Reactive
36
+ module RubiGenAffiliateMethod # :nodoc:
37
+
38
+ def affiliates(name, args, options)
39
+ klass.sources.collect {|source| source.collect}.flatten.each do |spec|
40
+ logger.affiliate(spec.name) do
41
+ self.class.new(spec.klass.new(args.dup, options)).invoke!
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ RubiGen::Commands::Base.send(:include, Reactive::RubiGenAffiliateMethod)
@@ -0,0 +1,62 @@
1
+ class SourceAnnotationExtractor # :nodoc: all
2
+ class Annotation < Struct.new(:line, :tag, :text)
3
+ def to_s(options={})
4
+ s = "[%3d] " % line
5
+ s << "[#{tag}] " if options[:tag]
6
+ s << text
7
+ end
8
+ end
9
+
10
+ def self.enumerate(tag, options={})
11
+ extractor = new(tag)
12
+ extractor.display(extractor.find, options)
13
+ end
14
+
15
+ attr_reader :tag
16
+
17
+ def initialize(tag)
18
+ @tag = tag
19
+ end
20
+
21
+ def find(dirs=%w(app lib test))
22
+ dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
23
+ end
24
+
25
+ def find_in(dir)
26
+ results = {}
27
+
28
+ Dir.glob("#{dir}/*") do |item|
29
+ next if File.basename(item)[0] == ?.
30
+
31
+ if File.directory?(item)
32
+ results.update(find_in(item))
33
+ elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
34
+ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
35
+ elsif item =~ /\.(rhtml|erb)$/
36
+ results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
37
+ end
38
+ end
39
+
40
+ results
41
+ end
42
+
43
+ def extract_annotations_from(file, pattern)
44
+ lineno = 0
45
+ result = File.readlines(file).inject([]) do |list, line|
46
+ lineno += 1
47
+ next list unless line =~ pattern
48
+ list << Annotation.new(lineno, $1, $2)
49
+ end
50
+ result.empty? ? {} : { file => result }
51
+ end
52
+
53
+ def display(results, options={})
54
+ results.keys.sort.each do |file|
55
+ puts "#{file}:"
56
+ results[file].each do |note|
57
+ puts " * #{note.to_s(options)}"
58
+ end
59
+ puts
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,23 @@
1
+ require 'source_annotation_extractor'
2
+
3
+ desc "Enumerate all annotations"
4
+ task :notes do
5
+ SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
6
+ end
7
+
8
+ namespace :notes do
9
+ desc "Enumerate all OPTIMIZE annotations"
10
+ task :optimize do
11
+ SourceAnnotationExtractor.enumerate "OPTIMIZE"
12
+ end
13
+
14
+ desc "Enumerate all FIXME annotations"
15
+ task :fixme do
16
+ SourceAnnotationExtractor.enumerate "FIXME"
17
+ end
18
+
19
+ desc "Enumerate all TODO annotations"
20
+ task :todo do
21
+ SourceAnnotationExtractor.enumerate "TODO"
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ namespace :app do
2
+ desc "Create the application gem package"
3
+ task :package => :environment do
4
+ require 'rubygems'
5
+ require 'rake/gempackagetask'
6
+
7
+ spec = Gem::Specification.new do |s|
8
+ s.files = []
9
+ Reactive.configuration.app_gem_spec(s)
10
+ s.name = APP_NAME
11
+ s.platform = Gem::Platform::RUBY
12
+ Dir.chdir(APP_PATH) do
13
+ s.files += Dir.glob("{app,assets,config,db,gems,lib,log}/**/*").delete_if {|item| item.include?("CVS") || item.include?("rdoc") || item.include?(".svn")}
14
+ s.files += Dir.entries('.').select {|name| File.file? name}
15
+ end
16
+ #s.add_dependency "reactive-core", "= #{Reactive::VERSION::STRING}"
17
+ #s.add_dependency "reactive-dev", "= #{Reactive::VERSION::STRING}"
18
+ end
19
+
20
+ filename = Gem::Builder.new(spec).build
21
+ FileUtils.move filename, File.join(APP_PATH, "pkg")
22
+ end
23
+
24
+ namespace :package do
25
+ WINDOZE = /djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
26
+ if WINDOZE
27
+ desc "Create a NSIS installer for the application\nPass APP_HUMAN_NAME='Fancy App Name' for the installer display name"
28
+ task :nsis => :package do
29
+ Dir.chdir(File.join(APP_PATH, 'pkg/nsis')) do
30
+ args = []
31
+ if File.file?(File.join(APP_PATH, 'License.txt'))
32
+ args << "/DLICENSE"
33
+ else
34
+ puts "Installer will have no License page. Put a License.txt in your app root to have one."
35
+ end
36
+ args << "/DRUBYSETUP" if ENV['RUBYSETUP']
37
+ args << "/DPRODUCT_NAME=#{APP_NAME}"
38
+ args << "/DPRODUCT_VERSION=#{Reactive.configuration.app_gem_spec.version}"
39
+ args << "/DPRODUCT_HUMAN_NAME=#{ENV['APP_HUMAN_NAME'] || APP_NAME}"
40
+ puts `#{nsis_command} #{args * ' '} ReactiveApp.nsi`
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ def nsis_command
50
+ "C:\\Program Files\\NSIS\\makensis.exe"
51
+ end
@@ -0,0 +1,147 @@
1
+ require 'rubyforge'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ gem 'rdoc'
7
+ rescue Gem::LoadError
8
+ end
9
+
10
+ WINDOZE = /djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
11
+ DIFF = (WINDOZE ? 'diff.exe' : (system("gdiff", __FILE__, __FILE__) ? 'gdiff' : 'diff')) unless defined? DIFF
12
+
13
+ #
14
+ # Setup variables used across task definitions below
15
+ # spec: contains the gem specification
16
+ # rubyforge_name: project name for rubyforge
17
+ # need_tar: create and release tgz archive
18
+ # need_zip: create and release tar archive
19
+ # RDOC_OPTIONS: Default options for RDoc generation
20
+
21
+ RDOC_OPTIONS = %w{-x Manifest -x Rakefile -x .*\.rake} unless defined? RDOC_OPTIONS
22
+ RDOC_OPTIONS << '-d' if `which dot` =~ /\/dot/ unless ENV['NODOT'] unless WINDOZE
23
+ RDOC_OPTIONS.push('-m', 'README') if File.file? 'README'
24
+
25
+ need_tar = @need_tar.nil? ? true : @need_tar
26
+ need_zip = @need_zip.nil? ? false : @need_zip
27
+
28
+ required_fields = [:name, :author, :email, :summary]
29
+ auto_populate_fields = required_fields + [:version, :homepage, :description, :changes]
30
+
31
+ spec = @spec || Gem::Specification.new
32
+
33
+ spec.has_rdoc = true
34
+ spec.extra_rdoc_files |= ["README", "LICENSE", "TODO", "History"].select {|file| File.file? file}
35
+ spec.rdoc_options += RDOC_OPTIONS
36
+ spec.files |= File.read("Manifest").delete("\r").split(/\n/) if File.file? "Manifest"
37
+ spec.executables |= spec.files.grep(/^bin/) {|file| File.basename(file)}
38
+
39
+ readme = File.read("README").split(/^(=+ .*)$/)[1..-1] rescue []
40
+ unless readme.empty?
41
+ sections = readme.map {|sct| sct =~ /^=/ ? sct.strip.downcase.chomp(':').split.last : sct.strip}
42
+
43
+ header = sections.slice!(0,2)
44
+ pairs = header[1].split(/^(\w+)::/)
45
+ spec.name ||= header[0]
46
+ spec.rubyforge_project ||= spec.name.downcase
47
+ spec.summary ||= pairs.shift
48
+
49
+ Hash[*pairs].each do |key,value|
50
+ spec.send("#{key.downcase}=", value.chomp.strip)
51
+ end if pairs.size.modulo(2) == 0
52
+
53
+ sections = Hash[*sections]
54
+ spec.description ||= sections.values_at('description').join("\n\n")
55
+
56
+ if sections['requirements']
57
+ sections['requirements'].scan(/^\*(.+)$/).flatten.each {|req| spec.add_dependency(*req.strip.split(/\s+/, 2)) unless req.empty? }
58
+ end
59
+ end
60
+
61
+ spec.extend(Module.new { attr_accessor :changes })
62
+ spec.changes = File.read("History").split(/^(===.*)/)[1..2].join.strip if File.exists? "History"
63
+
64
+ unless spec.version ||= ENV['VERSION']
65
+ warn "To package this gem, the specification needs a version number. It can't be\nfound in the README, so please pass it on the command line with VERSION=x.y.z"
66
+ end
67
+
68
+ unless (fields = required_fields.select {|field| !spec.send(field)}).empty?
69
+ warn "The following required fields for the gem specification are left unset:"
70
+ warn " " + fields.join(', ')
71
+ warn "To correct this, either specify them in the @spec variable defined"
72
+ warn "at the top of the Rakefile, or write a correctly layed out README."
73
+ end
74
+
75
+ rubyforge_name = ENV["RUBYFORGE_NAME"] || spec.rubyforge_project
76
+
77
+ ###
78
+ #
79
+
80
+ #desc 'packages the plugin as a gem'
81
+ Rake::GemPackageTask.new(spec) do |package|
82
+ package.need_tar = need_tar
83
+ package.need_zip = need_zip
84
+ end
85
+
86
+ ###
87
+ #
88
+
89
+ desc 'Verify the manifest.'
90
+ task :check_manifest do
91
+ f = "Manifest.tmp"
92
+ require 'find'
93
+ files = []
94
+ exclusions = /tmp$|CVS|pkg|\.svn|\.git/
95
+ Find.find '.' do |path|
96
+ next unless File.file? path
97
+ next if path =~ exclusions
98
+ files << path[2..-1]
99
+ end
100
+ files = files.sort.join "\n"
101
+ File.open f, 'w' do |fp| fp.puts files end
102
+ system "#{DIFF} -du Manifest #{f}"
103
+ rm f
104
+ end
105
+
106
+ ###
107
+ #
108
+
109
+ desc 'Release the plugin and upload it to rubyforge.'
110
+ task :release => [:gem] do |t|
111
+ version = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
112
+ abort "Rubyforge project name needed, add it to your gem specification\nin the Rakefile or pass RUBYFORGE_NAME=name on the command line." unless rubyforge_name
113
+
114
+ rf = RubyForge.new.configure
115
+ puts "Logging in"
116
+ rf.login
117
+
118
+ name = spec.name
119
+ pkg = "pkg/#{name}-#{version}"
120
+
121
+ c = rf.userconfig
122
+ c["release_notes"] = spec.description if spec.description
123
+ c["release_changes"] = spec.changes if spec.changes
124
+ c["preformatted"] = true
125
+
126
+ files = [(need_tar ? "#{pkg}.tgz" : nil),
127
+ (need_zip ? "#{pkg}.zip" : nil),
128
+ "#{pkg}.gem"].compact
129
+
130
+ puts "Releasing #{name} #{version}"
131
+ rf.add_release rubyforge_name, name, version, *files
132
+ end
133
+
134
+ ###
135
+ #
136
+
137
+ Rake::RDocTask.new(:docs) do |rd|
138
+ rd.rdoc_dir = 'doc'
139
+ rd.options += RDOC_OPTIONS
140
+ rd.rdoc_files.push(*spec.files.select {|file| file =~ /^[^\/]+$|^lib\//})
141
+
142
+ name = spec.name
143
+ title = "#{name}-#{spec.version} Documentation"
144
+ title = "#{rubyforge_name}'s " + title if rubyforge_name != name
145
+
146
+ rd.options << "-t #{title}"
147
+ end
@@ -0,0 +1,7 @@
1
+ desc "Report code statistics (KLOCs, etc) from the application"
2
+ task :stats do
3
+ require 'code_statistics'
4
+ # gather all dirs, then merge the names which targets the same dir, finally sort the pairs by the dir's path
5
+ dirs = Reactive.configuration.paths.inject(Hash.new([])) {|hash, (name, dir)| hash[dir] << name}.sort.collect {|dir,names| [names.join(', '), dir]}
6
+ CodeStatistics.new(dirs).to_s
7
+ end
@@ -0,0 +1,118 @@
1
+ TEST_CHANGES_SINCE = Time.now - 600
2
+
3
+ # Look up tests for recently modified sources.
4
+ def recent_tests(source_pattern, test_path, touched_since = 10.minutes.ago)
5
+ FileList[source_pattern].map do |path|
6
+ if File.mtime(path) > touched_since
7
+ tests = []
8
+ source_dir = File.dirname(path).split("/")
9
+ source_file = File.basename(path, '.rb')
10
+
11
+ # Support subdirs in app/models and app/controllers
12
+ modified_test_path = source_dir.length > 2 ? "#{test_path}/" << source_dir[1..source_dir.length].join('/') : test_path
13
+
14
+ # For modified files in app/ run the tests for it. ex. /test/functional/account_controller.rb
15
+ test = "#{modified_test_path}/#{source_file}_test.rb"
16
+ tests.push test if File.exists?(test)
17
+
18
+ # For modified files in app, run tests in subdirs too. ex. /test/functional/account/*_test.rb
19
+ test = "#{modified_test_path}/#{File.basename(path, '.rb').sub("_controller","")}"
20
+ FileList["#{test}/*_test.rb"].each { |f| tests.push f } if File.exists?(test)
21
+
22
+ return tests
23
+
24
+ end
25
+ end.flatten.compact
26
+ end
27
+
28
+
29
+ # Recreated here from ActiveSupport because :uncommitted needs it before Reactive is available
30
+ module Kernel
31
+ def silence_stderr
32
+ old_stderr = STDERR.dup
33
+ STDERR.reopen(RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'NUL:' : '/dev/null')
34
+ STDERR.sync = true
35
+ yield
36
+ ensure
37
+ STDERR.reopen(old_stderr)
38
+ end
39
+ end
40
+
41
+ desc 'Test all units and functionals'
42
+ task :test do
43
+ errors = %w(test:units test:functionals test:integration).collect do |task|
44
+ begin
45
+ Rake::Task[task].invoke
46
+ nil
47
+ rescue => e
48
+ task
49
+ end
50
+ end.compact
51
+ abort "Errors running #{errors.to_sentence}!" if errors.any?
52
+ end
53
+
54
+ namespace :test do
55
+ Rake::TestTask.new(:recent => "db:test:prepare") do |t|
56
+ since = TEST_CHANGES_SINCE
57
+ touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } +
58
+ recent_tests('app/models/**/*.rb', 'test/unit', since) +
59
+ recent_tests('app/controllers/**/*.rb', 'test/functional', since)
60
+
61
+ t.libs << 'test'
62
+ t.verbose = true
63
+ t.test_files = touched.uniq
64
+ end
65
+ Rake::Task['test:recent'].comment = "Test recent changes"
66
+
67
+ Rake::TestTask.new(:uncommitted => "db:test:prepare") do |t|
68
+ def t.file_list
69
+ changed_since_checkin = silence_stderr { `svn status` }.map { |path| path.chomp[7 .. -1] }
70
+
71
+ models = changed_since_checkin.select { |path| path =~ /app[\\\/]models[\\\/].*\.rb/ }
72
+ controllers = changed_since_checkin.select { |path| path =~ /app[\\\/]controllers[\\\/].*\.rb/ }
73
+
74
+ unit_tests = models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" }
75
+ functional_tests = controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" }
76
+
77
+ unit_tests.uniq + functional_tests.uniq
78
+ end
79
+
80
+ t.libs << 'test'
81
+ t.verbose = true
82
+ end
83
+ Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion)"
84
+
85
+ Rake::TestTask.new(:units => "db:test:prepare") do |t|
86
+ t.libs << "test"
87
+ t.pattern = 'test/unit/**/*_test.rb'
88
+ t.verbose = true
89
+ end
90
+ Rake::Task['test:units'].comment = "Run the unit tests in test/unit"
91
+
92
+ Rake::TestTask.new(:functionals => "db:test:prepare") do |t|
93
+ t.libs << "test"
94
+ t.pattern = 'test/functional/**/*_test.rb'
95
+ t.verbose = true
96
+ end
97
+ Rake::Task['test:functionals'].comment = "Run the functional tests in test/functional"
98
+
99
+ Rake::TestTask.new(:integration => "db:test:prepare") do |t|
100
+ t.libs << "test"
101
+ t.pattern = 'test/integration/**/*_test.rb'
102
+ t.verbose = true
103
+ end
104
+ Rake::Task['test:integration'].comment = "Run the integration tests in test/integration"
105
+
106
+ Rake::TestTask.new(:plugins => :environment) do |t|
107
+ t.libs << "test"
108
+
109
+ if ENV['PLUGIN']
110
+ t.pattern = "vendor/plugins/#{ENV['PLUGIN']}/test/**/*_test.rb"
111
+ else
112
+ t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb'
113
+ end
114
+
115
+ t.verbose = true
116
+ end
117
+ Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)"
118
+ end