rucola 0.0.3 → 0.5.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.
- data/ChangeLog +468 -0
- data/History.txt +25 -0
- data/License.txt +1 -1
- data/Manifest.txt +32 -0
- data/README.txt +9 -67
- data/Rakefile +39 -31
- data/TODO +10 -18
- data/app_generators/rucola/rucola_generator.rb +15 -8
- data/app_generators/rucola/templates/Rakefile.erb +35 -7
- data/app_generators/rucola/templates/config/boot.rb +0 -1
- data/app_generators/rucola/templates/config/dependencies.rb +31 -0
- data/app_generators/rucola/templates/config/environment.rb +0 -1
- data/app_generators/rucola/templates/config/environments/debug.rb +13 -1
- data/app_generators/rucola/templates/config/environments/release.rb +15 -1
- data/app_generators/rucola/templates/config/environments/test.rb +7 -1
- data/app_generators/rucola/templates/misc/rb_main.rb.erb +12 -1
- data/app_generators/rucola/templates/project.pbxproj.erb +4 -0
- data/app_generators/rucola/templates/script/console +10 -0
- data/app_generators/rucola/templates/test/controllers/test_application_controller.rb +22 -10
- data/app_generators/rucola/templates/test/test_helper.rb +1 -0
- data/bin/rucola +4 -2
- data/lib/rucola/dependencies.rb +241 -0
- data/lib/rucola/dependencies/exclusions.rb +20 -0
- data/lib/rucola/dependencies/override_require_and_gem.rb +30 -0
- data/lib/rucola/dependencies/resolver.rb +68 -0
- data/lib/rucola/fsevents.rb +108 -0
- data/lib/rucola/initializer.rb +149 -117
- data/lib/rucola/log.rb +61 -0
- data/lib/rucola/nib.rb +3 -3
- data/lib/rucola/reloader.rb +39 -0
- data/lib/rucola/ruby_debug.rb +27 -0
- data/lib/rucola/rucola_support.rb +1 -2
- data/lib/rucola/rucola_support/core_ext.rb +4 -2
- data/lib/rucola/rucola_support/core_ext/objc.rb +9 -4
- data/lib/rucola/rucola_support/core_ext/objc/nsimage.rb +22 -0
- data/lib/rucola/rucola_support/core_ext/ruby.rb +11 -4
- data/lib/rucola/rucola_support/core_ext/ruby/file.rb +11 -0
- data/lib/rucola/rucola_support/core_ext/ruby/kernel.rb +16 -0
- data/lib/rucola/rucola_support/core_ext/ruby/object.rb +47 -0
- data/lib/rucola/rucola_support/core_ext/ruby/string.rb +8 -0
- data/lib/rucola/rucola_support/notifications/notifications.rb +26 -28
- data/lib/rucola/rucola_support/rc_app.rb +18 -0
- data/lib/rucola/tasks/dependencies.rake +49 -0
- data/lib/rucola/tasks/deploy.rake +131 -0
- data/lib/rucola/tasks/main.rake +39 -6
- data/lib/rucola/tasks/xcode.rake +54 -11
- data/lib/rucola/test_case.rb +138 -0
- data/lib/rucola/test_helper.rb +11 -5
- data/lib/rucola/version.rb +2 -2
- data/lib/rucola/xcode.rb +39 -9
- data/rucola_generators/controller/templates/test_controller_template.rb.erb +19 -7
- data/rucola_generators/simple_model/USAGE +5 -0
- data/rucola_generators/simple_model/simple_model_generator.rb +54 -0
- data/rucola_generators/simple_model/templates/simple_model.rb.erb +2 -0
- data/rucola_generators/simple_model/templates/test_simple_model.rb.erb +11 -0
- data/rucola_generators/window_controller/templates/test_window_controller_template.rb.erb +24 -13
- data/test/fixtures/dependencies/foo.rb +2 -0
- data/test/fixtures/dependencies/foo/bar.rb +0 -0
- data/test/fixtures/dependencies/foo/baz.rb +0 -0
- data/test/fixtures/dependencies/requires_fileutils.rb +1 -0
- data/test/fixtures/some_reloadable_class.rb +4 -0
- data/test/test_core_ext.rb +80 -0
- data/test/test_dependencies.rb +205 -0
- data/test/test_fsevents.rb +152 -0
- data/test/test_helper.rb +30 -1
- data/test/test_initializer.rb +56 -23
- data/test/test_log.rb +44 -0
- data/test/test_objc_core_ext.rb +23 -0
- data/test/test_rc_app.rb +5 -0
- data/test/test_reloader.rb +28 -0
- data/test/test_rucola_generator.rb +7 -0
- data/test/test_simple_model_generator.rb +48 -0
- data/test/test_xcode.rb +85 -5
- data/website/index.html +17 -91
- data/website/index.txt +14 -81
- data/website/template.rhtml +1 -1
- metadata +120 -76
data/lib/rucola/log.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Rucola
|
4
|
+
# The Log class is basically a wrapper around NSLog. It is a singleton class so you should get an instance using the instance
|
5
|
+
# class method instead of new.
|
6
|
+
#
|
7
|
+
# Rucola::Log.instance.fatal("Couldn't initialize application.")
|
8
|
+
#
|
9
|
+
# The Log class is generally accessed through the log method on Kernel.
|
10
|
+
#
|
11
|
+
# log.debug("%d exceptions caught, giving up", exceptions.length)
|
12
|
+
class Log
|
13
|
+
DEBUG = 0
|
14
|
+
INFO = 1
|
15
|
+
WARN = 2
|
16
|
+
ERROR = 3
|
17
|
+
FATAL = 4
|
18
|
+
UNKNOWN = 5
|
19
|
+
SILENT = 9
|
20
|
+
|
21
|
+
include Singleton
|
22
|
+
|
23
|
+
# Holds the current log level
|
24
|
+
attr_accessor :level
|
25
|
+
|
26
|
+
# Creates a new Log instance. Don't call this directly, call instance instead.
|
27
|
+
#
|
28
|
+
# log.instance
|
29
|
+
def initialize
|
30
|
+
@level = level_for_env
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug(*args); log(DEBUG, *args); end
|
34
|
+
def info(*args); log(INFO, *args); end
|
35
|
+
def warn(*args); log(WARN, *args); end
|
36
|
+
def error(*args); log(ERROR, *args); end
|
37
|
+
def fatal(*args); log(FATAL, *args); end
|
38
|
+
def unknown(*args); log(UNKNOWN, *args); end
|
39
|
+
|
40
|
+
# Returns default log level for the application environment.
|
41
|
+
#
|
42
|
+
# log.level_for_env #=> Log::ERROR
|
43
|
+
def level_for_env
|
44
|
+
case RCApp.env
|
45
|
+
when 'test'
|
46
|
+
SILENT
|
47
|
+
when 'debug'
|
48
|
+
DEBUG
|
49
|
+
when 'release'
|
50
|
+
ERROR
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Writes a message to the log is the current loglevel is equal or greater than the message_level.
|
55
|
+
#
|
56
|
+
# log.log(Log::DEBUG, "This is a debug message")
|
57
|
+
def log(message_level, *args)
|
58
|
+
OSX.NSLog(*args) if message_level >= level
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/rucola/nib.rb
CHANGED
@@ -2,7 +2,7 @@ require 'osx/cocoa'
|
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
4
|
module Rucola
|
5
|
-
module Nib
|
5
|
+
module Nib #:nodoc:
|
6
6
|
|
7
7
|
def self.backup(path)
|
8
8
|
nib = File.dirname(path)
|
@@ -18,7 +18,7 @@ module Rucola
|
|
18
18
|
FileUtils.cp_r(nib, backup)
|
19
19
|
end
|
20
20
|
|
21
|
-
class Classes
|
21
|
+
class Classes #:nodoc:
|
22
22
|
attr_reader :data
|
23
23
|
|
24
24
|
def self.open(classes_nib_path)
|
@@ -53,7 +53,7 @@ module Rucola
|
|
53
53
|
|
54
54
|
end
|
55
55
|
|
56
|
-
class KeyedObjects
|
56
|
+
class KeyedObjects #:nodoc:
|
57
57
|
attr_reader :data
|
58
58
|
|
59
59
|
def self.open(path)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rucola/fsevents'
|
2
|
+
require 'rubynode'
|
3
|
+
|
4
|
+
module Rucola
|
5
|
+
# The +Reloader+ watches the app/controllers path and reloads
|
6
|
+
# a class if it notices that a file has been changed.
|
7
|
+
module Reloader
|
8
|
+
class << self
|
9
|
+
# Start watching app/controllers for a file modification and reload that class.
|
10
|
+
def start!
|
11
|
+
Rucola::FSEvents.start_watching(Rucola::RCApp.controllers_path, Rucola::RCApp.models_path) do |events|
|
12
|
+
events.each { |event| reload(event.last_modified_file) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Reload a file (class).
|
17
|
+
def reload(file)
|
18
|
+
klass = File.to_const(file)
|
19
|
+
begin
|
20
|
+
File.read(file).parse_to_nodes
|
21
|
+
|
22
|
+
log.debug "Reloading class #{klass.name}:"
|
23
|
+
|
24
|
+
i_methods = klass.instance_methods(false)
|
25
|
+
log.debug "- Undefining instance methods: #{i_methods.inspect}"
|
26
|
+
i_methods.each { |mname| klass.send(:undef_method, mname) }
|
27
|
+
|
28
|
+
c_methods = klass.original_class_methods
|
29
|
+
log.debug "- Undefining class methods: #{c_methods.inspect}"
|
30
|
+
c_methods.each { |mname| klass.metaclass.send(:undef_method, mname) }
|
31
|
+
|
32
|
+
Kernel.load(file)
|
33
|
+
rescue SyntaxError => e
|
34
|
+
log.error "WARNING: Reloading the class #{klass.name} would have caused a parse error:\n#{e.message}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kernel
|
2
|
+
def debugger(steps = 1); end
|
3
|
+
end
|
4
|
+
|
5
|
+
module Rucola
|
6
|
+
module Debugger
|
7
|
+
def self.use! #:nodoc:
|
8
|
+
Kernel.module_eval do
|
9
|
+
# If enabled in the Configuration (default in `debug` environment is on), calling #debugger will try to load the ruby-debug gem.
|
10
|
+
# In other modes however any call to #debugger will be ignored.
|
11
|
+
# However, for performance reasons you still might want to take out any calls in a release build.
|
12
|
+
def debugger(steps = 1)
|
13
|
+
rucola_load_ruby_debug(steps)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def rucola_load_ruby_debug(steps) #:nodoc:
|
19
|
+
require 'ruby-debug'
|
20
|
+
debugger(steps)
|
21
|
+
rescue LoadError
|
22
|
+
log.error "The ruby-debug gem is needed to be able to use the debugger, but it wasn't found."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
1
|
+
$:.unshift(File.dirname(__FILE__)) #unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
2
|
|
4
3
|
require 'rucola_support/rc_app'
|
5
4
|
require 'rucola_support/initialize_hooks'
|
@@ -1,4 +1,9 @@
|
|
1
|
-
Dir[File.dirname(__FILE__) + "/objc/*.rb"].sort.each do |path|
|
2
|
-
|
3
|
-
|
4
|
-
end
|
1
|
+
# Dir[File.dirname(__FILE__) + "/objc/*.rb"].sort.each do |path|
|
2
|
+
# filename = File.basename(path)
|
3
|
+
# require "rucola_support/core_ext/objc/#{filename}"
|
4
|
+
# end
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
require 'objc/nsimage'
|
9
|
+
require 'objc/nsobject'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class OSX::NSImage
|
2
|
+
class << self
|
3
|
+
# This implementation adds app/assets to the search domain.
|
4
|
+
# So if for instance you have an image app/assets/some_img.png,
|
5
|
+
# you can then use OSX::NSImage.imageNamed('some_img') and it will be found.
|
6
|
+
def imageNamed(name)
|
7
|
+
if @assets_files.nil?
|
8
|
+
@assets_files = {}
|
9
|
+
Dir.glob("#{Rucola::RCApp.assets_path}/*.*").each do |file|
|
10
|
+
basename = File.basename(file).gsub(/\..*/, '')
|
11
|
+
@assets_files[basename] = file
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if image_file = (@assets_files[name.to_s] || @assets_files[name.to_s.gsub(/\..*/, '')])
|
16
|
+
alloc.initWithContentsOfFile image_file
|
17
|
+
else
|
18
|
+
super_imageNamed(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,4 +1,11 @@
|
|
1
|
-
Dir[File.dirname(__FILE__) + "/ruby/*.rb"].sort.each do |path|
|
2
|
-
|
3
|
-
|
4
|
-
end
|
1
|
+
# Dir[File.dirname(__FILE__) + "/ruby/*.rb"].sort.each do |path|
|
2
|
+
# filename = File.basename(path)
|
3
|
+
# require "rucola_support/core_ext/ruby/#{filename}"
|
4
|
+
# end
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
require 'ruby/file'
|
9
|
+
require 'ruby/object'
|
10
|
+
require 'ruby/string'
|
11
|
+
require 'ruby/kernel'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rucola/log'
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
# Returns a logger instance
|
5
|
+
#
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# log.level = Rucola::Log::DEBUG
|
9
|
+
# log.info "Couldn't load preferences, using defaults"
|
10
|
+
# log.debug "Initiating primary foton drive…"
|
11
|
+
#
|
12
|
+
# For more information see the Rucola::Log class.
|
13
|
+
def log
|
14
|
+
Rucola::Log.instance
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Object
|
2
|
+
# Returns a class's metaclass.
|
3
|
+
#
|
4
|
+
# class FooBar; end
|
5
|
+
# p FooBar.metaclass # => #<Class:FooBar>
|
6
|
+
def self.metaclass
|
7
|
+
class << self; self; end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns an array of all the class methods that were added by extending the class.
|
11
|
+
#
|
12
|
+
# class FooBar; end
|
13
|
+
#
|
14
|
+
# module Baz
|
15
|
+
# def a_new_class_method; end
|
16
|
+
# end
|
17
|
+
# FooBar.extend(Baz)
|
18
|
+
#
|
19
|
+
# FooBar.extended_class_methods # => ['a_new_class_method']
|
20
|
+
def self.extended_class_methods
|
21
|
+
metaclass.included_modules.map { |mod| mod.instance_methods }.flatten.uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns an array of all the class methods that were defined in this class
|
25
|
+
# without the ones that were defined in it's superclasses.
|
26
|
+
#
|
27
|
+
# class FooBar
|
28
|
+
# def self.a_original_class_method
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# class FooBarSubclass < FooBar
|
33
|
+
# def self.a_original_class_method_in_a_subclass
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# FooBarSubclass.own_class_methods # => ['a_original_class_method_in_a_subclass']
|
38
|
+
def self.own_class_methods
|
39
|
+
metaclass.instance_methods - superclass.metaclass.instance_methods
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns an array of all the class methods that were defined in only this class,
|
43
|
+
# so without class methods from any of it's superclasses or from extending it.
|
44
|
+
def self.original_class_methods
|
45
|
+
own_class_methods - extended_class_methods
|
46
|
+
end
|
47
|
+
end
|
@@ -1,34 +1,32 @@
|
|
1
1
|
require 'osx/cocoa'
|
2
2
|
|
3
3
|
module Rucola
|
4
|
-
module Notifications
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
4
|
+
module Notifications #:nodoc:
|
5
|
+
# This Notifications module will add a class method called +notify_on+, which registers
|
6
|
+
# your object for the given notification and executes the given block when the
|
7
|
+
# notification is posted to the OSX::NSNotificationCenter.defaultCenter.
|
8
|
+
#
|
9
|
+
# class FooController < OSX::NSObject
|
10
|
+
#
|
11
|
+
# notify_on OSX::NSApplicationDidFinishLaunchingNotification do |notification|
|
12
|
+
# puts "Application did finish launching."
|
13
|
+
# p notification
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # code
|
17
|
+
#
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# In addition to notify_on, you also get a method called notify which allows you to specify methods
|
21
|
+
# to be invoked when a notification is posted.
|
22
|
+
#
|
23
|
+
# class FooController < OSX::NSObject
|
24
|
+
# notify :some_method, :when => :application_did_finish_launching
|
25
|
+
#
|
26
|
+
# def some_method(notification)
|
27
|
+
# puts "Application finished launching"
|
28
|
+
# end
|
29
|
+
# end
|
32
30
|
module ClassMethods
|
33
31
|
# Add prefix shortcuts as a hash.
|
34
32
|
#
|
@@ -2,6 +2,16 @@ require 'rucola/info_plist'
|
|
2
2
|
|
3
3
|
module Rucola
|
4
4
|
module RCApp
|
5
|
+
# Returns the current RUBYCOCOA_ENV, which normally is 'debug' during development, test in the tests and 'release' in a release.
|
6
|
+
def env; RUBYCOCOA_ENV; end
|
7
|
+
module_function :env
|
8
|
+
def test?; env == 'test'; end
|
9
|
+
module_function :test?
|
10
|
+
def debug?; env == 'debug'; end
|
11
|
+
module_function :debug?
|
12
|
+
def release?; env == 'release'; end
|
13
|
+
module_function :release?
|
14
|
+
|
5
15
|
# Returns the path to the current source root of the application.
|
6
16
|
#
|
7
17
|
# So in debug & test mode this will point to your development source root.
|
@@ -106,5 +116,13 @@ module Rucola
|
|
106
116
|
Rucola::InfoPlist.open((RUBYCOCOA_ROOT + 'config/Info.plist').to_s).app_name
|
107
117
|
end
|
108
118
|
module_function :app_name
|
119
|
+
|
120
|
+
# Returns the path to the application support directory for this application.
|
121
|
+
#
|
122
|
+
# Rucola::RCApp.application_support_path #=> '/Users/eddy/Library/Application Support/MyApp/'
|
123
|
+
def application_support_path
|
124
|
+
File.join File.expand_path('~/Library/Application Support'), app_name
|
125
|
+
end
|
126
|
+
module_function :application_support_path
|
109
127
|
end
|
110
128
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rucola/dependencies'
|
2
|
+
|
3
|
+
namespace :dependencies do
|
4
|
+
THIRD_PARTY_DIR = (SOURCE_ROOT + '/vendor/third_party/').to_s
|
5
|
+
|
6
|
+
def dependencies_holder
|
7
|
+
deps = Rucola::Dependencies.load((SOURCE_ROOT + '/config/dependencies.rb').to_s)
|
8
|
+
deps.resolve!
|
9
|
+
deps
|
10
|
+
end
|
11
|
+
|
12
|
+
def file_types
|
13
|
+
if ENV['FILE_TYPES']
|
14
|
+
ENV['FILE_TYPES'].split(',').map {|t| t.strip.to_sym }
|
15
|
+
else
|
16
|
+
CONFIGURATION.dependency_types
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Lists all the dependencies and their required files. Use the FILE_TYPES env var to specify which files you'd like to include."
|
21
|
+
task :list do
|
22
|
+
Rucola::Dependencies.verbose = false
|
23
|
+
|
24
|
+
str = ''
|
25
|
+
dependencies_holder.dependencies.each do |dep|
|
26
|
+
str += "\nDependency '#{dep.pretty_print_name}' requires the following files:\n\n"
|
27
|
+
dep.required_files_of_types(file_types).each { |file| str += " #{file.full_path}\n" }
|
28
|
+
end
|
29
|
+
puts str
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Copies all the required files to 'vendor/third_party/'."
|
33
|
+
task :copy do
|
34
|
+
# Check if we have enough info to do a copy
|
35
|
+
if file_types.is_a?(Symbol) or !file_types.empty?
|
36
|
+
FileUtils.mkdir_p(THIRD_PARTY_DIR) unless File.exist?(THIRD_PARTY_DIR)
|
37
|
+
$VERBOSE = nil # we don't want all the warnings about constant being redefined.
|
38
|
+
dependencies_holder.copy_to(THIRD_PARTY_DIR, :types => file_types)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Removes the 'vendor/third_party/' directory."
|
43
|
+
task :clean do
|
44
|
+
if File.exist? THIRD_PARTY_DIR
|
45
|
+
puts "Removing #{THIRD_PARTY_DIR}"
|
46
|
+
FileUtils.rm_rf(THIRD_PARTY_DIR)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|