rugui 1.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.
- data/LICENSE +165 -0
- data/README +67 -0
- data/README.rdoc +67 -0
- data/Rakefile +56 -0
- data/VERSION.yml +4 -0
- data/bin/rugui +16 -0
- data/lib/rugui/base_controller.rb +194 -0
- data/lib/rugui/base_model.rb +22 -0
- data/lib/rugui/base_object.rb +73 -0
- data/lib/rugui/base_view.rb +302 -0
- data/lib/rugui/base_view_helper.rb +23 -0
- data/lib/rugui/configuration.rb +136 -0
- data/lib/rugui/framework_adapters/GTK.rb +233 -0
- data/lib/rugui/framework_adapters/Qt4.rb +171 -0
- data/lib/rugui/framework_adapters/base_framework_adapter.rb +90 -0
- data/lib/rugui/framework_adapters/framework_adapter_support.rb +35 -0
- data/lib/rugui/gem_builder.rb +21 -0
- data/lib/rugui/gem_dependency.rb +282 -0
- data/lib/rugui/initialize_hooks.rb +36 -0
- data/lib/rugui/initializer.rb +162 -0
- data/lib/rugui/log_support.rb +118 -0
- data/lib/rugui/observable_property_proxy.rb +73 -0
- data/lib/rugui/observable_property_support.rb +251 -0
- data/lib/rugui/plugin/loader.rb +77 -0
- data/lib/rugui/property_observer.rb +58 -0
- data/lib/rugui/signal_support.rb +57 -0
- data/lib/rugui/tasks/gems_application.rake +71 -0
- data/lib/rugui/tasks/rugui.rb +8 -0
- data/lib/rugui/tasks/rugui_framework.rb +4 -0
- data/lib/rugui/tasks/runner_application.rake +4 -0
- data/lib/rugui/tasks/spec_application.rake +64 -0
- data/lib/rugui/tasks/spec_framework.rake +27 -0
- data/lib/rugui/tasks/test_application.rake +77 -0
- data/lib/rugui/vendor_gem_source_index.rb +140 -0
- data/lib/rugui/version.rb +9 -0
- data/lib/rugui.rb +37 -0
- data/spec/framework/base_controller_spec.rb +48 -0
- data/spec/framework/base_model_spec.rb +13 -0
- data/spec/framework/base_view_helper_spec.rb +13 -0
- data/spec/framework/base_view_spec.rb +92 -0
- data/spec/framework/log_support_spec.rb +16 -0
- data/spec/framework/observable_property_proxy_spec.rb +67 -0
- data/spec/framework/observable_property_support_spec.rb +283 -0
- data/spec/framework/property_observer_spec.rb +88 -0
- data/spec/helpers/controllers.rb +29 -0
- data/spec/helpers/initialize_hooks_helper.rb +18 -0
- data/spec/helpers/models.rb +9 -0
- data/spec/helpers/observables.rb +210 -0
- data/spec/helpers/view_helpers.rb +9 -0
- data/spec/helpers/views.rb +72 -0
- data/spec/rcov.opts +1 -0
- data/spec/resource_files/my_other_view.glade +46 -0
- data/spec/resource_files/my_view.glade +46 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +15 -0
- metadata +149 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'Qt4'
|
2
|
+
require 'qtuitools'
|
3
|
+
|
4
|
+
module Qt
|
5
|
+
def Qt.create_application
|
6
|
+
@@application = Qt::Application.new(ARGV)
|
7
|
+
end
|
8
|
+
|
9
|
+
def Qt.application
|
10
|
+
@@application
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Qt.create_application
|
15
|
+
|
16
|
+
module RuGUI
|
17
|
+
module FrameworkAdapters
|
18
|
+
module Qt4
|
19
|
+
class BaseController < RuGUI::FrameworkAdapters::BaseFrameworkAdapter::BaseController
|
20
|
+
def queue(&block)
|
21
|
+
block.call
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class BaseMainController < RuGUI::FrameworkAdapters::Qt4::BaseController
|
26
|
+
def run
|
27
|
+
Qt.application.exec
|
28
|
+
end
|
29
|
+
|
30
|
+
def quit
|
31
|
+
Qt.application.exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class BaseView < RuGUI::FrameworkAdapters::BaseFrameworkAdapter::BaseView
|
36
|
+
# Queues the block call, so that it is only gets executed in the main thread.
|
37
|
+
def queue(&block)
|
38
|
+
block.call
|
39
|
+
end
|
40
|
+
|
41
|
+
# Adds a widget to the given container widget.
|
42
|
+
def add_widget_to_container(widget, container_widget)
|
43
|
+
widget.parent = container_widget
|
44
|
+
end
|
45
|
+
|
46
|
+
# Removes a widget from the given container widget.
|
47
|
+
def remove_widget_from_container(widget, container_widget)
|
48
|
+
widget.parent = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Removes all children from the given container widget.
|
52
|
+
def remove_all_children(container_widget)
|
53
|
+
container_widget.children.each do |child|
|
54
|
+
child.parent = nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets the widget name for the given widget if given.
|
59
|
+
def set_widget_name(widget, widget_name)
|
60
|
+
widget.object_name = widget_name
|
61
|
+
end
|
62
|
+
|
63
|
+
# Autoconnects signals handlers for the view. If +other_target+ is given
|
64
|
+
# it is used instead of the view itself.
|
65
|
+
def autoconnect_signals(view, other_target = nil)
|
66
|
+
# Qt4 doesn't provides a method for autoconnecting signals.
|
67
|
+
end
|
68
|
+
|
69
|
+
# Connects the signal from the widget to the given receiver block.
|
70
|
+
# The block is executed in the context of the receiver.
|
71
|
+
def connect_declared_signal_block(widget, signal, receiver, block)
|
72
|
+
widget.connect(SIGNAL(signal)) do |*args|
|
73
|
+
receiver.instance_exec(*args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Connects the signal from the widget to the given receiver method.
|
78
|
+
def connect_declared_signal(widget, signal, receiver, method)
|
79
|
+
widget.connect(SIGNAL(signal)) do |*args|
|
80
|
+
receiver.send(method, *args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Builds widgets from the given filename, using the proper builder.
|
85
|
+
def build_widgets_from(filename)
|
86
|
+
ui_file_root_widget = load_ui_file(filename)
|
87
|
+
@view_root_widget = root_widget_from(ui_file_root_widget)
|
88
|
+
create_attributes_for_widget_and_children(@view_root_widget)
|
89
|
+
@view_root_widget.show if self.adapted_object.display_root?
|
90
|
+
end
|
91
|
+
|
92
|
+
# Registers widgets as attributes of the view class.
|
93
|
+
def register_widgets
|
94
|
+
register_widget_and_children(@view_root_widget)
|
95
|
+
end
|
96
|
+
|
97
|
+
class << self
|
98
|
+
# Returns the builder file extension to be used for this view class.
|
99
|
+
def builder_file_extension
|
100
|
+
'ui'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
def load_ui_file(filename)
|
106
|
+
file = Qt::File.new(filename)
|
107
|
+
file.open(Qt::File::ReadOnly)
|
108
|
+
loader = Qt::UiLoader.new
|
109
|
+
loader.load(file, nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
def root_widget_from(ui_file_root_widget)
|
113
|
+
self.adapted_object.root.nil? ? ui_file_root_widget : find_child(ui_file_root_widget, self.adapted_object.root)
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_attributes_for_widget_and_children(widget)
|
117
|
+
self.adapted_object.send(:create_attribute_for_widget, widget.object_name)
|
118
|
+
widget.children.each do |child|
|
119
|
+
create_attributes_for_widget_and_children(child) unless child.object_name.blank?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Registers widgets as attributes of the view class.
|
124
|
+
def register_widget_and_children(widget)
|
125
|
+
register_widget(widget)
|
126
|
+
widget.children.each do |child|
|
127
|
+
register_widget_and_children(child)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def register_widget(widget)
|
132
|
+
unless widget.object_name.nil?
|
133
|
+
self.adapted_object.send("#{widget.object_name}=", widget)
|
134
|
+
self.adapted_object.widgets[widget.object_name] = widget
|
135
|
+
else
|
136
|
+
self.adapted_object.unnamed_widgets << widget
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# XXX: Qt's find_child is not working, so we do it ourselves, this is surely not optimal.
|
141
|
+
def find_child(widget, widget_name)
|
142
|
+
for child in widget.children
|
143
|
+
if child.object_name == widget_name
|
144
|
+
return child
|
145
|
+
else
|
146
|
+
child_found = find_child(child, widget_name)
|
147
|
+
return child_found unless child_found.blank?
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
module RuGUI
|
157
|
+
class BaseView < BaseObject
|
158
|
+
# An utility method to connect Qt signals between two Qt::Object.
|
159
|
+
#
|
160
|
+
# If receiver is given, it will be used instead of the view itself.
|
161
|
+
def connect(sender, signal, slot, receiver = nil)
|
162
|
+
sender = from_widget_or_name(sender)
|
163
|
+
receiver = receiver.nil? ? self : from_widget_or_name(receiver)
|
164
|
+
if receiver.is_a?(Qt::Object)
|
165
|
+
Qt::Object.connect(sender, SIGNAL(signal), receiver, SLOT(slot))
|
166
|
+
elsif receiver.is_a?(RuGUI::BaseObject)
|
167
|
+
sender.connect(SIGNAL(signal)) { |*args| receiver.send(slot, *args) if receiver.respond_to?(slot) }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module RuGUI
|
2
|
+
module FrameworkAdapters
|
3
|
+
module BaseFrameworkAdapter
|
4
|
+
class Base
|
5
|
+
attr_accessor :adapted_object
|
6
|
+
|
7
|
+
def initialize(adapted_object)
|
8
|
+
self.adapted_object = adapted_object
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adapts the BaseController methods specific for the framework.
|
13
|
+
class BaseController < Base
|
14
|
+
# Queues the block call, so that it is only gets executed in the main thread.
|
15
|
+
def queue(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adapts the BaseMainController methods specific for the framework.
|
20
|
+
class BaseMainController < RuGUI::FrameworkAdapters::BaseFrameworkAdapter::BaseController
|
21
|
+
# Runs the application, starting anything the framework needs.
|
22
|
+
def run
|
23
|
+
end
|
24
|
+
|
25
|
+
# Exits the application, freeing any resources used by the framework.
|
26
|
+
def quit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Adapts the BaseModel methods specific for the framework
|
31
|
+
class BaseModel < Base
|
32
|
+
end
|
33
|
+
|
34
|
+
# Adapts the BaseView methods specific for the framework
|
35
|
+
class BaseView < Base
|
36
|
+
# Queues the block call, so that it is only gets executed in the main thread.
|
37
|
+
def queue(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Adds a widget to the given container widget.
|
41
|
+
def add_widget_to_container(widget, container_widget)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Removes a widget from the given container widget.
|
45
|
+
def remove_widget_from_container(widget, container_widget)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Removes all children from the given container widget.
|
49
|
+
def remove_all_children(container_widget)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sets the widget name for the given widget if given.
|
53
|
+
def set_widget_name(widget, widget_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Autoconnects signals handlers for the view. If +other_target+ is given
|
57
|
+
# it is used instead of the view itself.
|
58
|
+
def autoconnect_signals(view, other_target = nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Connects the signal from the widget to the given receiver block.
|
62
|
+
# The block is executed in the context of the receiver.
|
63
|
+
def connect_declared_signal_block(widget, signal, receiver, block)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Connects the signal from the widget to the given receiver method.
|
67
|
+
def connect_declared_signal(widget, signal, receiver, method)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Builds widgets from the given filename, using the proper builder.
|
71
|
+
def build_widgets_from(filename)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Registers widgets as attributes of the view class.
|
75
|
+
def register_widgets
|
76
|
+
end
|
77
|
+
|
78
|
+
class << self
|
79
|
+
# Returns the builder file extension to be used for this view class.
|
80
|
+
def builder_file_extension
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Adapts the BaseViewHelper methods specific for the framework
|
86
|
+
class BaseViewHelper
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rugui/framework_adapters/base_framework_adapter'
|
2
|
+
|
3
|
+
module RuGUI
|
4
|
+
module FrameworkAdapters
|
5
|
+
module FrameworkAdapterSupport
|
6
|
+
def framework_adapter_for(class_name)
|
7
|
+
@framework_adapter ||= {}
|
8
|
+
load_framework_adapter(class_name) unless @framework_adapter[class_name]
|
9
|
+
@framework_adapter[class_name]
|
10
|
+
end
|
11
|
+
|
12
|
+
def load_framework_adapter(class_name)
|
13
|
+
@framework_adapter[class_name] = class_adapter_for(class_name).new(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
module CommonClassAndInstanceMethods
|
17
|
+
def adapter_module_name(framework_adapter = RuGUI.configuration.framework_adapter)
|
18
|
+
"RuGUI::FrameworkAdapters::#{framework_adapter.camelize}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def class_adapter_for(class_name)
|
22
|
+
"#{adapter_module_name}::#{class_name}".constantize
|
23
|
+
rescue
|
24
|
+
# Fallback to the base_framework_adapter.
|
25
|
+
"#{adapter_module_name('base_framework_adapter')}::#{class_name}".constantize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.included(base)
|
30
|
+
base.send(:include, CommonClassAndInstanceMethods)
|
31
|
+
base.extend(CommonClassAndInstanceMethods)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/installer'
|
3
|
+
|
4
|
+
module RuGUI
|
5
|
+
|
6
|
+
# this class hijacks the functionality of Gem::Installer by overloading its
|
7
|
+
# initializer to only provide the information needed by
|
8
|
+
# Gem::Installer#build_extensions (which happens to be what we have)
|
9
|
+
class GemBuilder < Gem::Installer
|
10
|
+
|
11
|
+
def initialize(spec, gem_dir)
|
12
|
+
@spec = spec
|
13
|
+
@gem_dir = gem_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
# silence the underlying builder
|
17
|
+
def say(message)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,282 @@
|
|
1
|
+
require 'rugui/vendor_gem_source_index'
|
2
|
+
|
3
|
+
module Gem
|
4
|
+
def self.source_index=(index)
|
5
|
+
@@source_index = index
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module RuGUI
|
10
|
+
class GemDependency < Gem::Dependency
|
11
|
+
attr_accessor :lib, :source, :dep
|
12
|
+
|
13
|
+
def self.unpacked_path
|
14
|
+
@unpacked_path ||= File.join(APPLICATION_ROOT, 'vendor', 'gems')
|
15
|
+
end
|
16
|
+
|
17
|
+
@@framework_gems = {}
|
18
|
+
|
19
|
+
def self.add_frozen_gem_path
|
20
|
+
@@paths_loaded ||= begin
|
21
|
+
source_index = RuGUI::VendorGemSourceIndex.new(Gem.source_index)
|
22
|
+
Gem.clear_paths
|
23
|
+
Gem.source_index = source_index
|
24
|
+
# loaded before us - we can't change them, so mark them
|
25
|
+
Gem.loaded_specs.each do |name, spec|
|
26
|
+
@@framework_gems[name] = spec
|
27
|
+
end
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(name, options = {})
|
33
|
+
require 'rubygems' unless Object.const_defined?(:Gem)
|
34
|
+
|
35
|
+
if options[:requirement]
|
36
|
+
req = options[:requirement]
|
37
|
+
elsif options[:version]
|
38
|
+
req = Gem::Requirement.create(options[:version])
|
39
|
+
else
|
40
|
+
req = Gem::Requirement.default
|
41
|
+
end
|
42
|
+
|
43
|
+
@lib = options[:lib]
|
44
|
+
@source = options[:source]
|
45
|
+
@loaded = @frozen = @load_paths_added = false
|
46
|
+
|
47
|
+
super(name, req)
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_load_paths
|
51
|
+
self.class.add_frozen_gem_path
|
52
|
+
return if @loaded || @load_paths_added
|
53
|
+
if framework_gem?
|
54
|
+
@load_paths_added = @loaded = @frozen = true
|
55
|
+
return
|
56
|
+
end
|
57
|
+
gem self
|
58
|
+
@spec = Gem.loaded_specs[name]
|
59
|
+
@frozen = @spec.loaded_from.include?(self.class.unpacked_path) if @spec
|
60
|
+
@load_paths_added = true
|
61
|
+
rescue Gem::LoadError
|
62
|
+
end
|
63
|
+
|
64
|
+
def dependencies
|
65
|
+
return [] if framework_gem?
|
66
|
+
return [] unless installed?
|
67
|
+
specification.dependencies.reject do |dependency|
|
68
|
+
dependency.type == :development
|
69
|
+
end.map do |dependency|
|
70
|
+
GemDependency.new(dependency.name, :requirement => dependency.version_requirements)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def specification
|
75
|
+
# code repeated from Gem.activate. Find a matching spec, or the currently loaded version.
|
76
|
+
# error out if loaded version and requested version are incompatible.
|
77
|
+
@spec ||= begin
|
78
|
+
matches = Gem.source_index.search(self)
|
79
|
+
matches << @@framework_gems[name] if framework_gem?
|
80
|
+
if Gem.loaded_specs[name] then
|
81
|
+
# This gem is already loaded. If the currently loaded gem is not in the
|
82
|
+
# list of candidate gems, then we have a version conflict.
|
83
|
+
existing_spec = Gem.loaded_specs[name]
|
84
|
+
unless matches.any? { |spec| spec.version == existing_spec.version } then
|
85
|
+
raise Gem::Exception,
|
86
|
+
"can't activate #{@dep}, already activated #{existing_spec.full_name}"
|
87
|
+
end
|
88
|
+
# we're stuck with it, so change to match
|
89
|
+
version_requirements = Gem::Requirement.create("=#{existing_spec.version}")
|
90
|
+
existing_spec
|
91
|
+
else
|
92
|
+
# new load
|
93
|
+
matches.last
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def requirement
|
99
|
+
r = version_requirements
|
100
|
+
(r == Gem::Requirement.default) ? nil : r
|
101
|
+
end
|
102
|
+
|
103
|
+
def built?
|
104
|
+
# TODO: If Rubygems ever gives us a way to detect this, we should use it
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
def framework_gem?
|
109
|
+
@@framework_gems.has_key?(name)
|
110
|
+
end
|
111
|
+
|
112
|
+
def frozen?
|
113
|
+
@frozen ||= vendor_rugui? || vendor_gem?
|
114
|
+
end
|
115
|
+
|
116
|
+
def installed?
|
117
|
+
Gem.loaded_specs.keys.include?(name)
|
118
|
+
end
|
119
|
+
|
120
|
+
def load_paths_added?
|
121
|
+
# always try to add load paths - even if a gem is loaded, it may not
|
122
|
+
# be a compatible version (ie random_gem 0.4 is loaded and a later spec
|
123
|
+
# needs >= 0.5 - gem 'random_gem' will catch this and error out)
|
124
|
+
@load_paths_added
|
125
|
+
end
|
126
|
+
|
127
|
+
def loaded?
|
128
|
+
@loaded ||= begin
|
129
|
+
if vendor_rugui?
|
130
|
+
true
|
131
|
+
elsif specification.nil?
|
132
|
+
false
|
133
|
+
else
|
134
|
+
# check if the gem is loaded by inspecting $"
|
135
|
+
# specification.files lists all the files contained in the gem
|
136
|
+
gem_files = specification.files
|
137
|
+
# select only the files contained in require_paths - typically in bin and lib
|
138
|
+
require_paths_regexp = Regexp.new("^(#{specification.require_paths*'|'})/")
|
139
|
+
gem_lib_files = gem_files.select { |f| require_paths_regexp.match(f) }
|
140
|
+
# chop the leading directory off - a typical file might be in
|
141
|
+
# lib/gem_name/file_name.rb, but it will be 'require'd as gem_name/file_name.rb
|
142
|
+
gem_lib_files.map! { |f| f.split('/', 2)[1] }
|
143
|
+
# if any of the files from the above list appear in $", the gem is assumed to
|
144
|
+
# have been loaded
|
145
|
+
!(gem_lib_files & $").empty?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def vendor_rugui?
|
151
|
+
Gem.loaded_specs.has_key?(name) && Gem.loaded_specs[name].loaded_from.empty?
|
152
|
+
end
|
153
|
+
|
154
|
+
def vendor_gem?
|
155
|
+
specification && File.exists?(unpacked_gem_directory)
|
156
|
+
end
|
157
|
+
|
158
|
+
def build
|
159
|
+
require 'rugui/gem_builder'
|
160
|
+
unless built?
|
161
|
+
return unless File.exists?(unpacked_specification_filename)
|
162
|
+
spec = YAML::load_file(unpacked_specification_filename)
|
163
|
+
RuGUI::GemBuilder.new(spec, unpacked_gem_directory).build_extensions
|
164
|
+
puts "Built gem: '#{unpacked_gem_directory}'"
|
165
|
+
end
|
166
|
+
dependencies.each { |dep| dep.build }
|
167
|
+
end
|
168
|
+
|
169
|
+
def install
|
170
|
+
unless installed?
|
171
|
+
cmd = "#{gem_command} #{install_command.join(' ')}"
|
172
|
+
puts cmd
|
173
|
+
puts %x(#{cmd})
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def load
|
178
|
+
return if @loaded || @load_paths_added == false
|
179
|
+
require(@lib || name) unless @lib == false
|
180
|
+
@loaded = true
|
181
|
+
rescue LoadError
|
182
|
+
puts $!.to_s
|
183
|
+
$!.backtrace.each { |b| puts b }
|
184
|
+
end
|
185
|
+
|
186
|
+
def refresh
|
187
|
+
RuGUI::VendorGemSourceIndex.silence_spec_warnings = true
|
188
|
+
real_gems = Gem.source_index.installed_source_index
|
189
|
+
exact_dep = Gem::Dependency.new(name, "= #{specification.version}")
|
190
|
+
matches = real_gems.search(exact_dep)
|
191
|
+
installed_spec = matches.first
|
192
|
+
if frozen?
|
193
|
+
if installed_spec
|
194
|
+
# we have a real copy
|
195
|
+
# get a fresh spec - matches should only have one element
|
196
|
+
# note that there is no reliable method to check that the loaded
|
197
|
+
# spec is the same as the copy from real_gems - Gem.activate changes
|
198
|
+
# some of the fields
|
199
|
+
real_spec = Gem::Specification.load(matches.first.loaded_from)
|
200
|
+
write_specification(real_spec)
|
201
|
+
puts "Reloaded specification for #{name} from installed gems."
|
202
|
+
else
|
203
|
+
# the gem isn't installed locally - write out our current specs
|
204
|
+
write_specification(specification)
|
205
|
+
puts "Gem #{name} not loaded locally - writing out current spec."
|
206
|
+
end
|
207
|
+
else
|
208
|
+
if framework_gem?
|
209
|
+
puts "Gem directory for #{name} not found - check if it's loading before rugui."
|
210
|
+
else
|
211
|
+
puts "Something bad is going on - gem directory not found for #{name}."
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def unpack(options={})
|
217
|
+
unless frozen? || framework_gem?
|
218
|
+
FileUtils.mkdir_p unpack_base
|
219
|
+
Dir.chdir unpack_base do
|
220
|
+
Gem::GemRunner.new.run(unpack_command)
|
221
|
+
end
|
222
|
+
# Gem.activate changes the spec - get the original
|
223
|
+
real_spec = Gem::Specification.load(specification.loaded_from)
|
224
|
+
write_specification(real_spec)
|
225
|
+
end
|
226
|
+
dependencies.each { |dep| dep.unpack } if options[:recursive]
|
227
|
+
end
|
228
|
+
|
229
|
+
def write_specification(spec)
|
230
|
+
# copy the gem's specification into GEMDIR/.specification so that
|
231
|
+
# we can access information about the gem on deployment systems
|
232
|
+
# without having the gem installed
|
233
|
+
File.open(unpacked_specification_filename, 'w') do |file|
|
234
|
+
file.puts spec.to_yaml
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def ==(other)
|
239
|
+
self.name == other.name && self.requirement == other.requirement
|
240
|
+
end
|
241
|
+
alias_method :"eql?", :"=="
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def gem_command
|
246
|
+
case RUBY_PLATFORM
|
247
|
+
when /win32/
|
248
|
+
'gem.bat'
|
249
|
+
when /java/
|
250
|
+
'jruby -S gem'
|
251
|
+
else
|
252
|
+
'gem'
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def install_command
|
257
|
+
cmd = %w(install) << name
|
258
|
+
cmd << "--version" << %("#{requirement.to_s}") if requirement
|
259
|
+
cmd << "--source" << @source if @source
|
260
|
+
cmd
|
261
|
+
end
|
262
|
+
|
263
|
+
def unpack_command
|
264
|
+
cmd = %w(unpack) << name
|
265
|
+
cmd << "--version" << "= "+specification.version.to_s if requirement
|
266
|
+
cmd
|
267
|
+
end
|
268
|
+
|
269
|
+
def unpack_base
|
270
|
+
RuGUI::GemDependency.unpacked_path
|
271
|
+
end
|
272
|
+
|
273
|
+
def unpacked_gem_directory
|
274
|
+
File.join(unpack_base, specification.full_name)
|
275
|
+
end
|
276
|
+
|
277
|
+
def unpacked_specification_filename
|
278
|
+
File.join(unpacked_gem_directory, '.specification')
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RuGUI
|
2
|
+
# Adds before/after hooks for initialize method of a class.
|
3
|
+
module InitializeHooks
|
4
|
+
def self.included(base)
|
5
|
+
self.update_initialize_method(base)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.update_initialize_method(base)
|
9
|
+
base.class_eval <<-class_eval
|
10
|
+
alias :original_initialize :initialize
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
initialize_with_hooks(*args)
|
14
|
+
end
|
15
|
+
class_eval
|
16
|
+
end
|
17
|
+
|
18
|
+
# Calls the original initialize method with before/after hooks.
|
19
|
+
def initialize_with_hooks(*args)
|
20
|
+
before_initialize
|
21
|
+
original_initialize(*args)
|
22
|
+
after_initialize
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
# Called before the initialize method. Subclasses can reimplement this in
|
27
|
+
# order to have custom behavior.
|
28
|
+
def before_initialize
|
29
|
+
end
|
30
|
+
|
31
|
+
# Called after the initialize method. Subclasses can reimplement this in
|
32
|
+
# order to have custom behavior.
|
33
|
+
def after_initialize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|