freightrain 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/README +4 -0
  2. data/Rakefile +33 -0
  3. data/lib/extensions/gtk/dialog_helper.rb +50 -0
  4. data/lib/extensions/gtk/gtk_bootstrapper.rb +32 -0
  5. data/lib/extensions/gtk/interface_builder.rb +54 -0
  6. data/lib/extensions/gtk/widgets/gtk_calendar.rb +18 -0
  7. data/lib/extensions/gtk/widgets/gtk_combo_box.rb +41 -0
  8. data/lib/extensions/gtk/widgets/gtk_image.rb +14 -0
  9. data/lib/extensions/gtk/widgets/gtk_layout.rb +99 -0
  10. data/lib/extensions/gtk/widgets/gtk_toggle_button.rb +13 -0
  11. data/lib/extensions/gtk/widgets/gtk_toggle_tool_button.rb +11 -0
  12. data/lib/extensions/gtk/widgets/gtk_treeview.rb +80 -0
  13. data/lib/extensions/gtk/widgets/gtk_treeviewcolumn.rb +29 -0
  14. data/lib/extensions/gtk/widgets/gtk_widget.rb +47 -0
  15. data/lib/freightrain/auto_requirer.rb +24 -0
  16. data/lib/freightrain/binding/binding_host.rb +35 -0
  17. data/lib/freightrain/binding/binding_loader.rb +36 -0
  18. data/lib/freightrain/binding/converters/boolean_converter.rb +15 -0
  19. data/lib/freightrain/binding/converters/converter_factory.rb +22 -0
  20. data/lib/freightrain/binding/converters/default_converter.rb +16 -0
  21. data/lib/freightrain/binding/converters/float_converter.rb +16 -0
  22. data/lib/freightrain/binding/converters/integer_converter.rb +16 -0
  23. data/lib/freightrain/binding/freight_binding.rb +65 -0
  24. data/lib/freightrain/bootstrapper.rb +35 -0
  25. data/lib/freightrain/dialog_extension.rb +27 -0
  26. data/lib/freightrain/elements/element_extension.rb +1 -0
  27. data/lib/freightrain/elements/freight_element_view.rb +23 -0
  28. data/lib/freightrain/elements/freight_element_view_model.rb +42 -0
  29. data/lib/freightrain/elements/layout_widget.rb +11 -0
  30. data/lib/freightrain/freight_view.rb +52 -0
  31. data/lib/freightrain/freight_view_model.rb +45 -0
  32. data/lib/freightrain/interface_builder.rb +23 -0
  33. data/lib/freightrain/ioc/container.rb +21 -0
  34. data/lib/freightrain/ioc/container_hookable.rb +32 -0
  35. data/lib/freightrain/regions/freight_region.rb +32 -0
  36. data/lib/freightrain/regions/region_host.rb +37 -0
  37. data/lib/freightrain/services/freight_service.rb +14 -0
  38. data/lib/freightrain/services/service_host.rb +30 -0
  39. data/lib/freightrain/signals/freight_signal.rb +23 -0
  40. data/lib/freightrain/signals/signal_host.rb +38 -0
  41. data/lib/freightrain/string_patch.rb +24 -0
  42. data/lib/freightrain/testhelpers/container_helpers.rb +22 -0
  43. data/lib/freightrain/testhelpers.rb +2 -0
  44. data/lib/freightrain.rb +8 -0
  45. data/lib/scaffolding/commands/app.rb +29 -0
  46. data/lib/scaffolding/commands/triad.rb +29 -0
  47. data/lib/scaffolding/ftrain.rb +23 -0
  48. data/lib/scaffolding/generator.rb +15 -0
  49. data/lib/scaffolding/templates/application.ftt +11 -0
  50. data/lib/scaffolding/templates/view.ftt +5 -0
  51. data/lib/scaffolding/templates/view_bnd.ftt +0 -0
  52. data/lib/scaffolding/templates/view_control_glade.ftt +16 -0
  53. data/lib/scaffolding/templates/view_model.ftt +7 -0
  54. data/lib/scaffolding/templates/view_toplevel_glade.ftt +12 -0
  55. metadata +127 -0
@@ -0,0 +1,16 @@
1
+
2
+ module Freightrain
3
+
4
+ class FloatConverter
5
+
6
+ def from(value)
7
+ return value.to_s
8
+ end
9
+
10
+ def to(value)
11
+ return value.to_f
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module Freightrain
3
+
4
+ class IntegerConverter
5
+
6
+ def from(value)
7
+ return value.to_s
8
+ end
9
+
10
+ def to(value)
11
+ return value.to_i
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,65 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightBinding
5
+
6
+ def initialize(widget, options)
7
+ @cache = :__NOVALUE
8
+ @widget = widget
9
+ @property = options[:property].to_s.split('.')
10
+ @path = options[:path].to_s.split('.')
11
+ @converter = ConverterFactory.create(options[:converter]) || DefaultConverter.new
12
+ @force = options[:force]
13
+ end
14
+
15
+ def data_source
16
+ return @data_source
17
+ end
18
+
19
+ def data_source=(source)
20
+ @data_source = source
21
+ end
22
+
23
+ def update()
24
+ begin
25
+ value = get(data_source, @path)
26
+ if @force || value != @cache
27
+ set(@property, @converter.from(value), @widget)
28
+ @cache = value
29
+ end
30
+ rescue Exception => ex
31
+ # p "#{@widget.name} - update"
32
+ # p ex.message
33
+ # p @path
34
+ end
35
+ end
36
+
37
+ def commit()
38
+ begin
39
+ value = get(@widget, @property)
40
+ set(@path, @converter.to(value), data_source)
41
+ rescue Exception => ex
42
+ # p "#{@widget.name} - commit"
43
+ # p ex.message
44
+ # p @path
45
+ end
46
+ end
47
+
48
+ private
49
+ def get(source, path)
50
+ my_path = path.clone
51
+ return source.send(my_path[0]) if my_path.length == 1
52
+ target = my_path.shift
53
+ get(source.send(target), my_path)
54
+ end
55
+
56
+ def set(path, value, source)
57
+ my_path = path.clone
58
+ return source.send(my_path[0].to_s + "=",value) if my_path.length == 1
59
+ target = my_path.shift
60
+ set(my_path, value, source.send(target))
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,35 @@
1
+
2
+ module Freightrain
3
+
4
+ attr_accessor :toolkit
5
+ attr_accessor :app_path
6
+
7
+ def views_path
8
+ base_path = File.join(@app_path, "views")
9
+ toolkit_path = File.join(base_path, @toolkit.to_s)
10
+ return toolkit_path if File.exist?(toolkit_path)
11
+ return base_path
12
+ end
13
+
14
+ def load_extensions!()
15
+ begin
16
+ require File.dirname(__FILE__) + "/../extensions/#{@toolkit.to_s}/#{@toolkit.to_s}_bootstrapper.rb"
17
+ rescue Exception => ex
18
+ p "Could not load #{@toolkit}. Have you installed all the required libraries?"
19
+ p "Exception : "
20
+ p ex
21
+ end
22
+ end
23
+
24
+ def start(viewmodel_name)
25
+ @toolkit ||= :gtk
26
+ load_extensions!
27
+ auto_require!
28
+ configure_container!
29
+ yield if block_given?
30
+ Toolkit.start_main_loop do
31
+ Freightrain[(viewmodel_name.to_s + "_view_model").to_sym].show
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,27 @@
1
+
2
+ module Freightrain
3
+
4
+ module DialogExtension
5
+
6
+ def show_dialog(*args)
7
+ on_show(*args)
8
+ @on_close = lambda { |*params| yield(*params) } if block_given?
9
+ @view.update
10
+ show
11
+ end
12
+
13
+ def on_show(*args)
14
+ #to be overridden
15
+ end
16
+
17
+ def close(*args)
18
+ @on_close.call(*args) if @on_close
19
+ hide
20
+ end
21
+
22
+ def cancel
23
+ hide
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightElementView < FreightView
5
+ extend ContainerHookable
6
+
7
+ def self.container_options
8
+ return { :model => :prototype }
9
+ end
10
+
11
+ def update
12
+ @signals.values.each { |signal| signal.stifle }
13
+ super
14
+ @signals.values.each { |signal| signal.unleash }
15
+ end
16
+
17
+ def initialize
18
+ super
19
+ @signals[:selected] = FreightSignal.new
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightElementViewModel < FreightViewModel
5
+ extend ContainerHookable
6
+
7
+ attr_reader :selected
8
+
9
+ def self.container_options
10
+ return { :model => :prototype }
11
+ end
12
+
13
+ def value=(val)
14
+ @value = val
15
+ @view.update
16
+ end
17
+
18
+ def value
19
+ return @value
20
+ end
21
+
22
+ def on_selected
23
+ fire :selected, @value
24
+ end
25
+
26
+ def control
27
+ return @view.control
28
+ end
29
+
30
+ def initialize
31
+ super
32
+ @signals[:selected] = FreightSignal.new
33
+ end
34
+
35
+ def set_selection(bool)
36
+ @selected = bool
37
+ @view.update
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Freightrain
3
+ module LayoutWidget
4
+
5
+ def add_signal_callback(signal, proc)
6
+ @signals ||= {}
7
+ @signals[signal] = proc
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightView
5
+ include InterfaceBuilder
6
+ include BindingHost
7
+ extend SignalHost
8
+ extend ContainerHookable
9
+
10
+ # attr_reader :widgets
11
+
12
+ def widgets
13
+ return @widgets.select { |widget| widget.kind_of? Gtk::Widget}
14
+ end
15
+
16
+ def self.container_options
17
+ return {:model => :prototype}
18
+ end
19
+
20
+ def control
21
+ return @builder.control
22
+ end
23
+
24
+ def toplevel
25
+ return control.toplevel
26
+ end
27
+
28
+ def initialize()
29
+ @widgets = []
30
+ if(Freightrain.toolkit)
31
+ self.class.instance_eval("include Toolkit::DialogHelper")
32
+ @builder = Freightrain.get_interface_builder
33
+ load_from_file(self.class.name, @builder)
34
+ end
35
+ hook_to_layout_widgets()
36
+ load_bindings_from_file(@widgets)
37
+ create_signals
38
+ end
39
+
40
+ def hook_to_layout_widgets
41
+ @widgets.select{ |widget| widget.is_a? LayoutWidget }.each do |widget|
42
+ method_prefix = widget.name + "_on_"
43
+ self.methods.select { |method_name| method_name =~ /#{method_prefix}/}.each do |method_name|
44
+ signal_name = method_name.sub(method_prefix, "")
45
+ widget.add_signal_callback(signal_name.to_sym, method(method_name))
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,45 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightViewModel
5
+ extend ContainerHookable
6
+ extend ServiceHost
7
+ extend RegionHost
8
+ extend SignalHost
9
+
10
+ def self.container_options
11
+ return { :model => :prototype }
12
+ end
13
+
14
+ def dialog(viewmodel_name, *args)
15
+ dialog = Freightrain["#{viewmodel_name}_view_model".to_sym]
16
+ dialog.show_dialog(*args) do |*params|
17
+ yield(*params) if block_given?
18
+ end
19
+ end
20
+
21
+ def initialize()
22
+ @view = Freightrain[self.class.name.sub("Model", "").to_convention_sym]
23
+ get_services
24
+ build_regions
25
+ create_signals
26
+ @view.signals.each do |key,signal|
27
+ signal.connect(method("on_#{key}")) if self.respond_to? "on_#{key}"
28
+ end
29
+ @view.data_source = self
30
+ end
31
+
32
+ def show
33
+ @view.control.visible = true
34
+ @regions.values.each do |region|
35
+ region.on_show(@view)
36
+ end
37
+ return @view.control
38
+ end
39
+
40
+ def hide
41
+ @view.control.visible = false
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Freightrain
3
+
4
+ def get_interface_builder
5
+ return Toolkit::InterfaceBuilder.new
6
+ end
7
+
8
+ module InterfaceBuilder
9
+
10
+ def load_from_file(file_name, builder)
11
+ if builder.file_found?(file_name)
12
+ @widgets = builder.create_objects_from_file(file_name)
13
+ builder.create_object_accessors(@widgets, self)
14
+ builder.connect_signals do |signal|
15
+ if self.respond_to? signal
16
+ method(signal)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Freightrain
3
+
4
+ def configure_container!(registry = Needle::Registry.new)
5
+
6
+ @registry = registry
7
+
8
+ ContainerHookable.classes.each do |klass|
9
+ klass.subclasses.each do |subclass|
10
+ @registry.register(
11
+ subclass.name.to_convention_sym, subclass.container_options) { subclass.new }
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ def [](class_name)
18
+ return @registry.send(class_name)
19
+ end
20
+
21
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module Freightrain
3
+
4
+ module ContainerHookable
5
+
6
+ def self.extended(extending_class)
7
+ @@classes ||= []
8
+ @@classes << extending_class
9
+ extending_class.instance_variable_set(:@container_options, {})
10
+ end
11
+
12
+ def self.classes
13
+ @@classes ||= []
14
+ return @@classes
15
+ end
16
+
17
+ def inherited(subclass)
18
+ @subclasses ||= []
19
+ @subclasses << subclass
20
+ end
21
+
22
+ def container_options
23
+ return {}
24
+ end
25
+
26
+ def subclasses
27
+ return @subclasses || []
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightRegion
5
+
6
+ def initialize(name, options)
7
+ @name = name
8
+ viewmodel_name = options[:viewmodel] || @name
9
+ @viewmodel = Freightrain[(viewmodel_name.to_s + "_view_model").to_sym]
10
+ @container = @name.to_s + "_region"
11
+ end
12
+
13
+ def viewmodel
14
+ return @viewmodel
15
+ end
16
+
17
+ def on_show(view)
18
+ container = view.send(@container)
19
+ container.plug_in(@viewmodel.show)
20
+ end
21
+
22
+ def connect_to(host)
23
+ @viewmodel.signals.each do |key, signal|
24
+ if host.respond_to? "#{@name.to_s}_on_#{key.to_s}".to_sym
25
+ signal.connect(host.method("#{@name.to_s}_on_#{key.to_s}".to_sym))
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module RegionHost
3
+
4
+ def self.extended(klass)
5
+
6
+ klass.class_eval do
7
+
8
+ def build_regions
9
+ region_definitions = self.class.instance_variable_get(:@regions)
10
+ region_definitions ||= []
11
+ @regions = {}
12
+ region_definitions.each do |name, options|
13
+ @regions[name] = FreightRegion.new(name, options)
14
+ self.class.send(:define_method, name) do
15
+ return @regions[name].viewmodel
16
+ end
17
+ @regions[name].connect_to(self)
18
+ end
19
+ end
20
+
21
+ def change_region(region_name, viewmodel_name)
22
+ region = FreightRegion.new(region_name, {:viewmodel => viewmodel_name})
23
+ region.connect_to(self)
24
+ region.on_show(@view)
25
+ @regions[region_name] = region
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ def region(name, options = {})
33
+ @regions ||= {}
34
+ @regions[name.to_sym] = options
35
+ end
36
+
37
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightService
5
+ extend ContainerHookable
6
+ extend ServiceHost
7
+
8
+ def initialize
9
+ get_services
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,30 @@
1
+
2
+
3
+ module Freightrain
4
+
5
+ module ServiceHost
6
+
7
+ def self.extended(klass)
8
+
9
+ klass.class_eval do
10
+
11
+ def get_services
12
+ services = self.class.instance_variable_get(:@services)
13
+ services ||= []
14
+ services.each do |service|
15
+ eval "@#{service} = Freightrain[:#{service.to_s}_service]"
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+
22
+ def service(name)
23
+ @services ||= []
24
+ @services << name.to_sym
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
@@ -0,0 +1,23 @@
1
+
2
+ module Freightrain
3
+
4
+ class FreightSignal
5
+
6
+ def fire(*args)
7
+ @proc.call(*args) if @proc && !@inactive
8
+ end
9
+
10
+ def connect(proc)
11
+ @proc = proc
12
+ end
13
+
14
+ def stifle
15
+ @inactive = true
16
+ end
17
+
18
+ def unleash
19
+ @inactive = false
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+
2
+
3
+ module Freightrain
4
+
5
+ module SignalHost
6
+
7
+ def self.extended(klass)
8
+
9
+ klass.class_eval do
10
+
11
+ def fire(signal, *args)
12
+ @signals[signal.to_sym].fire(*args)
13
+ end
14
+
15
+ def signals
16
+ return @signals
17
+ end
18
+
19
+ def create_signals
20
+ @signals = {}
21
+ signals = self.class.instance_variable_get(:@signals)
22
+ signals ||= []
23
+ signals.each do |signal|
24
+ @signals[signal] = FreightSignal.new
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+
31
+ def signal(signal_name)
32
+ @signals ||= []
33
+ @signals << signal_name.to_sym
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,24 @@
1
+
2
+ class String
3
+
4
+ def to_convention
5
+ return "" if self.empty?
6
+ clone = self.clone
7
+ first_letter = clone.slice!(0)
8
+ result = first_letter.chr.downcase
9
+ clone.each_char do |letter|
10
+ if letter =~ /^[A-Z]/
11
+ result += "_"
12
+ result += letter.downcase
13
+ else
14
+ result += letter
15
+ end
16
+ end
17
+ return result.downcase
18
+ end
19
+
20
+ def to_convention_sym
21
+ return nil if self.to_convention.empty?
22
+ return self.to_convention.to_sym
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+
2
+ require 'rubygems'
3
+ require 'freightrain'
4
+
5
+
6
+ module Freightrain
7
+
8
+ def inject(name, object)
9
+ @registry ||= Needle::Registry.new
10
+ @registry.register(name) { object }
11
+ end
12
+
13
+ end
14
+
15
+ class Object
16
+
17
+ def inject_service(name, object)
18
+ Freightrain.inject(name.to_s + "_service", object)
19
+ end
20
+
21
+ end
22
+
@@ -0,0 +1,2 @@
1
+
2
+ require File.dirname(__FILE__) + '/testhelpers/container_helpers.rb'
@@ -0,0 +1,8 @@
1
+
2
+ require 'rubygems'
3
+
4
+ require 'needle'
5
+ require 'require_all'
6
+ require 'tmpdir'
7
+
8
+ require_all File.dirname(__FILE__) + '/freightrain'
@@ -0,0 +1,29 @@
1
+
2
+ class AppCommand
3
+
4
+ def initialize(*args)
5
+ raise "name parameter must be specified" if args.length < 1
6
+ @name = args[0]
7
+ @dir = Dir.pwd
8
+ @path = File.join(@dir, @name)
9
+ end
10
+
11
+ def check
12
+ raise "Directory #{@name} already exists" if File.exist?(File.join(@dir, @name))
13
+ end
14
+
15
+ def execute
16
+ FileUtils.mkdir(@path)
17
+ FileUtils.mkdir(File.join(@path, "views"))
18
+ FileUtils.mkdir(File.join(@path, "viewmodels"))
19
+ FileUtils.mkdir(File.join(@path, "services"))
20
+ FileUtils.mkdir(File.join(@path, "domain"))
21
+ Generator.create_stub(File.join(@path, "#{@name}.rb"),"application", :name => @name)
22
+ Generator.create_stub(File.join(@path, "views", "#{@name}_view.rb"), "view", :name => @name.capitalize)
23
+ Generator.create_stub(File.join(@path, "views", "#{@name}_view.glade"), "view_toplevel_glade",:name => @name)
24
+ Generator.create_stub(File.join(@path, "views", "#{@name}_view.bnd.yml"), "view_bnd", :name => @name)
25
+ Generator.create_stub(File.join(@path, "viewmodels", "#{@name}_view_model.rb"), "view_model", :name => @name.capitalize)
26
+ print "Application created in #{@path}\n"
27
+ end
28
+
29
+ end