freightrain 0.5.9

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.
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