ruby_mvc 0.0.1 → 0.0.2

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 (68) hide show
  1. data/README.md +14 -0
  2. data/lib/ruby_mvc.rb +3 -1
  3. data/lib/ruby_mvc/application.rb +52 -2
  4. data/lib/ruby_mvc/controllers.rb +28 -0
  5. data/lib/ruby_mvc/controllers/action.rb +93 -0
  6. data/lib/ruby_mvc/controllers/action_group.rb +70 -0
  7. data/lib/ruby_mvc/controllers/app_controller.rb +4 -2
  8. data/lib/ruby_mvc/controllers/rails_controller.rb +2 -0
  9. data/lib/ruby_mvc/models.rb +2 -0
  10. data/lib/ruby_mvc/models/ar_table_model.rb +133 -0
  11. data/lib/ruby_mvc/models/array_table_model.rb +81 -13
  12. data/lib/ruby_mvc/models/keyed_array_table_model.rb +1 -1
  13. data/lib/ruby_mvc/models/model.rb +129 -0
  14. data/lib/ruby_mvc/models/table_model.rb +107 -10
  15. data/lib/ruby_mvc/models/view_model_template.rb +140 -0
  16. data/lib/ruby_mvc/renderers.rb +1 -0
  17. data/lib/ruby_mvc/renderers/html4_table_model_renderer.rb +7 -6
  18. data/lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb +47 -0
  19. data/lib/ruby_mvc/toolkit.rb +5 -1
  20. data/lib/ruby_mvc/toolkit/browser_history.rb +115 -0
  21. data/lib/ruby_mvc/toolkit/dialog.rb +12 -1
  22. data/lib/ruby_mvc/toolkit/frame.rb +3 -1
  23. data/lib/ruby_mvc/toolkit/grid_view.rb +46 -0
  24. data/lib/ruby_mvc/toolkit/messagebox.rb +32 -0
  25. data/lib/ruby_mvc/toolkit/peers/wxruby.rb +5 -0
  26. data/lib/ruby_mvc/toolkit/peers/wxruby/app.rb +23 -2
  27. data/lib/ruby_mvc/toolkit/peers/wxruby/common.rb +11 -1
  28. data/lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb +82 -0
  29. data/lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb +108 -0
  30. data/lib/ruby_mvc/toolkit/peers/wxruby/frame.rb +85 -1
  31. data/lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb +79 -0
  32. data/lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb +117 -0
  33. data/lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb +58 -0
  34. data/lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb +40 -10
  35. data/lib/ruby_mvc/toolkit/property_change_notifier.rb +46 -0
  36. data/lib/ruby_mvc/toolkit/signal_handler.rb +149 -0
  37. data/lib/ruby_mvc/toolkit/web_view.rb +1 -1
  38. data/lib/ruby_mvc/toolkit/widget.rb +13 -6
  39. data/lib/ruby_mvc/views.rb +8 -59
  40. data/lib/ruby_mvc/views/{ar_type_list.rb → ar_form_view.rb} +10 -13
  41. data/lib/ruby_mvc/views/ar_support.rb +29 -0
  42. data/lib/ruby_mvc/views/ar_type_editor.rb +17 -28
  43. data/lib/ruby_mvc/views/ar_web_model_view.rb +59 -0
  44. data/lib/ruby_mvc/views/ar_web_type_list.rb +44 -0
  45. data/lib/ruby_mvc/views/browser_view.rb +185 -0
  46. data/lib/ruby_mvc/views/form_view.rb +111 -0
  47. data/lib/ruby_mvc/views/grid_table_view.rb +96 -0
  48. data/lib/ruby_mvc/views/table_view.rb +0 -39
  49. data/lib/ruby_mvc/views/view.rb +121 -0
  50. data/lib/ruby_mvc/views/web_content_table_view.rb +40 -0
  51. data/lib/ruby_mvc/views/{web_view.rb → web_content_view.rb} +17 -28
  52. data/lib/ruby_mvc/views/web_model_view.rb +67 -0
  53. data/ruby_mvc.gemspec +1 -1
  54. data/sample/browser_view.rb +57 -0
  55. data/sample/form.rb +59 -0
  56. data/sample/form2.rb +63 -0
  57. data/sample/grid_table_view.rb +68 -0
  58. data/sample/grid_view.rb +44 -0
  59. data/sample/grid_view2.rb +57 -0
  60. data/sample/test.html +1 -0
  61. data/sample/test2.html +33 -0
  62. data/sample/web_view.rb +4 -0
  63. data/test/unit/models/test_array_table_model.rb +19 -3
  64. data/test/unit/models/test_keyed_array_table_model.rb +3 -2
  65. data/test/unit/models/test_model.rb +88 -0
  66. metadata +39 -20
  67. data/lib/ruby_mvc/toolkit/notification.rb +0 -202
  68. data/lib/ruby_mvc/views/ar_model_editor.rb +0 -84
@@ -38,29 +38,32 @@ module RubyMVC
38
38
  evt_html_link_clicked self, :on_link_clicked
39
39
  #evt_html_cell_hover self, :on_hover
40
40
  end
41
+ @history = BrowserHistory.new
41
42
  end
42
43
 
43
- attr_reader :location
44
+ def location
45
+ @history.current
46
+ end
44
47
 
45
48
  def can_go_back?
46
- history_can_back
49
+ @history.has_prev?
47
50
  end
48
51
 
49
52
  def can_go_forward?
50
- history_can_forward
53
+ @history.has_next?
51
54
  end
52
55
 
53
56
  def go_back
54
- history_back
57
+ load_entry @history.prev
55
58
  end
56
59
 
57
60
  def go_forward
58
- history_forward
61
+ load_entry @history.next
59
62
  end
60
63
 
61
64
  def open(uri)
62
- @location = uri
63
- load_page(uri)
65
+ @history << { :uri => uri }
66
+ load_entry(@history.current)
64
67
  end
65
68
 
66
69
  def stop_loading
@@ -68,13 +71,30 @@ module RubyMVC
68
71
  end
69
72
 
70
73
  def reload
71
- open(location)
74
+ load_entry(@history.current)
72
75
  end
73
76
 
74
77
  def load_html(html, base_uri = nil)
75
78
  # FIXME: this isn't quite right...
76
- set_page(html)
77
- @location = base_uri
79
+ if base_uri
80
+ if base_uri != @history.current[:uri]
81
+ @history << { :uri => base_uri, :content => html }
82
+ else
83
+ @history.current[:content] = html
84
+ end
85
+ else
86
+ @history << { :uri => base_uri, :content => html }
87
+ end
88
+ load_entry(@history.current)
89
+ end
90
+
91
+ def append_html(html = "", &block)
92
+ # FIXME: not sure if I want to keep this API as it
93
+ # seems kinda clunky...
94
+ h = html || ""
95
+ h << block.call if block
96
+ @history.current[:content] << h
97
+ append_to_page(h)
78
98
  end
79
99
 
80
100
  #--
@@ -89,6 +109,16 @@ module RubyMVC
89
109
  signal_emit("navigation-requested", self, link.href, link.target)
90
110
  end
91
111
 
112
+ protected
113
+ def load_entry(entry)
114
+ if html = entry[:content]
115
+ set_page(html)
116
+ else
117
+ load_page(entry[:uri])
118
+ end
119
+ signal_emit("load-finished", self, entry[:uri])
120
+ end
121
+
92
122
  end
93
123
  end
94
124
  end
@@ -0,0 +1,46 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011-2012 Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: property_change_notifier.rb
21
+ # Created: Mon 2 Jan 2012 12:52:02 CET
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Toolkit
28
+
29
+ module PropertyChangeNotifier
30
+ include Toolkit::SignalHandler
31
+ extend Toolkit::SignalHandler::ClassMethods
32
+
33
+ # this signal is emitted when any property is changed on
34
+ # the model. The arguments are the sender, the old and
35
+ # the new values
36
+
37
+ signal "property-changed"
38
+
39
+ protected
40
+ def property_changed(key, old, val)
41
+ signal_emit("property-changed", self, key, old, val)
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,149 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2008, Andrew S. Townley
5
+ #
6
+ # Permission to use, copy, modify, and disribute this software for
7
+ # any purpose with or without fee is hereby granted, provided that
8
+ # the above copyright notices and this permission notice appear in
9
+ # all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
12
+ # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14
+ # AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
15
+ # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
17
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
+ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
+ #
20
+ # File: signal_handler.rb
21
+ # Author: Andrew S. Townley
22
+ # Created: Sat Nov 1 14:27:10 GMT 2008
23
+ # Borrowed: Wed 23 Nov 2011 22:29:22 GMT
24
+ #
25
+ ######################################################################
26
+ #++
27
+
28
+ module RubyMVC
29
+ module Toolkit
30
+
31
+ # This module provides an implementation of signal handlers
32
+ # originally modelled on the GTK+ 2.x mechanisms. While it
33
+ # is similar to GTK+, it may not behave in exactly the same
34
+ # way.
35
+ #
36
+ # This module also defines some useful class methods to
37
+ # expand the meta-programming of Ruby objects to support
38
+ # signal handling. To use these methods, you follow the
39
+ # following idiom in the derived class:
40
+ #
41
+ # class SignalSource
42
+ # incude RubyMVC::Toolkit::SignalHandler
43
+ # extend RubyMVC::Toolkit::SignalHandler::ClassMethods
44
+ # ...
45
+ # end
46
+ #
47
+ # Once the class has been defined as per above, valid
48
+ # signals for the signal source may be defined using the
49
+ # class method #signal as follows:
50
+ #
51
+ # class SignalSource
52
+ # ...
53
+ #
54
+ # signal "sig1", :description => "A test signal",
55
+ # signal "sig2", :description => "A vetoable signal", :vetoable => true
56
+ # ...
57
+ # end
58
+ #
59
+ # To register for signal notification, use the
60
+ # #signal_connect method of the signal source instance as
61
+ # follows:
62
+ #
63
+ # src = SignalSource.new
64
+ # src.signal_connect "sig1" do |sender|
65
+ # ...
66
+ # end
67
+ #
68
+ # Internally to the signal source instance, the signal can
69
+ # be triggered using the #signal_emit method as follows
70
+ #
71
+ # class SignalSource
72
+ # def send_sig1
73
+ # ...
74
+ # signal_emit("sig1", self)
75
+ # ...
76
+ # end
77
+ # end
78
+ #
79
+ # Planned Areas of Improvement
80
+ # ============================
81
+ #
82
+ # Currently, there's not a really good way to document the
83
+ # signals so that they're clear. I'm not sure how these are
84
+ # represented in rdoc, but there should be a method/way to
85
+ # specify the arguments in order and what they should be so
86
+ # that they live with the signal definition within the class
87
+ # itself so things are self-documenting.
88
+
89
+ module SignalHandler
90
+ module ClassMethods
91
+ def signals
92
+ @signals ||= {}
93
+ end
94
+
95
+ def signal(signal, options = { :vetoable => false })
96
+ signals[signal] = options
97
+ end
98
+
99
+ def valid_signal?(signal)
100
+ # puts "#{self}#signals.keys: #{signals.keys.inspect}"
101
+ # puts "#{self}#signals.has_key? #{signal}: #{signals.has_key?(signal)}"
102
+ # if self.superclass.respond_to?(:valid_signal?)
103
+ # puts "#{self.superclass}#signals.keys: #{self.superclass.signals.keys.inspect}"
104
+ # puts "#{self.superclass}#valid_signal? #{signal}: #{self.superclass.valid_signal?(signal)}"
105
+ # end
106
+
107
+ return true if signals.has_key? signal
108
+
109
+ if self.superclass.respond_to? :valid_signal?
110
+ self.superclass.valid_signal? signal
111
+ else
112
+ false
113
+ end
114
+ end
115
+
116
+ def valid_signal!(signal)
117
+ if !valid_signal? (signal)
118
+ raise ArgumentError, "class #{self} does not support signal '#{signal}'"
119
+ end
120
+ end
121
+ end
122
+
123
+ def signal_connect(signal, &block)
124
+ self.class.valid_signal! signal if self.class.respond_to? :signals
125
+ signals = (@signals ||= {})
126
+ sigs = (signals[signal] ||= [])
127
+ if !sigs.include? block
128
+ sigs << block
129
+ end
130
+ end
131
+
132
+ def signal_disconnect(signal, &block)
133
+ self.class.valid_signal! signal if self.class.respond_to? :signals
134
+ signals = (@signals ||= {})
135
+ sigs = (signals[signal] ||= [])
136
+ sigs.delete(block)
137
+ end
138
+
139
+ def signal_emit(signal, *args)
140
+ self.class.valid_signal! signal if self.class.respond_to? :signals
141
+ signals = (@signals ||= {})
142
+ (signals[signal] ||= []).each do |proc|
143
+ proc.call(*args) if !proc.nil?
144
+ end
145
+ end
146
+ end
147
+
148
+ end
149
+ end
@@ -30,7 +30,7 @@ module RubyMVC
30
30
  # modelled on WebKit
31
31
 
32
32
  class WebView < Widget
33
- api_method :load_html
33
+ api_methods :load_html, :append_html
34
34
  api_methods :can_go_back?, :go_back
35
35
  api_methods :can_go_forward?, :go_forward
36
36
  api_methods :open, :reload, :go_home, :location
@@ -25,15 +25,22 @@
25
25
 
26
26
  module RubyMVC
27
27
  module Toolkit
28
-
29
- # This class defines the base toolkit widget class. Each
30
- # widget has one - and only one - UI peer that is
31
- # registered automatically when the UI peer is loaded.
32
28
 
33
- class Widget
29
+ # This class provides an un-peered abstract widget, mostly
30
+ # related to signal handling capabilities so that
31
+ # abstract, non-peer views can be created with built-in
32
+ # signal handling.
33
+
34
+ class AbstractWidget
34
35
  include SignalHandler
35
36
  extend SignalHandler::ClassMethods
37
+ end
38
+
39
+ # This class defines the base toolkit widget class. Each
40
+ # widget has one - and only one - UI peer that is
41
+ # registered automatically when the UI peer is loaded.
36
42
 
43
+ class Widget < AbstractWidget
37
44
  class << self
38
45
  attr_accessor :peer_class
39
46
 
@@ -96,7 +103,7 @@ module RubyMVC
96
103
 
97
104
  def connect_peer_signals
98
105
  self.class.signals.each do |s, opts|
99
- puts "connecting signal '#{s}' to #{peer}"
106
+ puts "connecting signal '#{peer}##{s}' to #{self}"
100
107
  peer.signal_connect(s) do |*args|
101
108
  args[0] = self
102
109
  signal_emit(s, *args)
@@ -23,63 +23,12 @@
23
23
  #####################################################################
24
24
  #++
25
25
 
26
- module RubyMVC
27
- module Views
28
-
29
- class View
30
- def self.widget_def(targ = nil)
31
- if targ == nil
32
- @widget_def
33
- else
34
- if (x = targ.widget_def).nil?
35
- if targ != RubyMVC::Views::View
36
- self.widget_def(targ.superclass)
37
- end
38
- else
39
- x
40
- end
41
- end
42
- end
43
-
44
- def self.create_widget(klass)
45
- w = self.widget_def(klass)
46
- args = w[:args]
47
- block = w[:block]
48
- args[0].new(*args[1..-1], &block)
49
- end
50
-
51
- class << self
52
- # This method is used to define the primary widget
53
- # class through which this view may be added to other
54
- # widgets.
55
-
56
- def widget(*args, &block)
57
- puts "Set widget for #{self}: #{args.inspect}"
58
- @widget_def = { :args => args, :block => block }
59
- end
60
- end
61
-
62
- def peer
63
- @widget.peer
64
- end
65
-
66
- attr_accessor :controller, :widget
67
- def initialize(*args)
68
- @widget = View.create_widget(self.class)
69
- if(options = args.last).is_a? Hash
70
- self.controller = options[:controller]
71
- end
72
- end
73
-
74
- def method_missing(m, *a, &b)
75
- @widget.send(m, *a, &b)
76
- end
77
- end
78
- end
79
- end
80
-
26
+ require 'ruby_mvc/views/view'
27
+ require 'ruby_mvc/views/web_content_view'
28
+ require 'ruby_mvc/views/web_model_view'
29
+ require 'ruby_mvc/views/web_content_table_view'
30
+ require 'ruby_mvc/views/form_view'
31
+ require 'ruby_mvc/views/grid_table_view'
32
+ require 'ruby_mvc/views/browser_view'
81
33
  #require 'ruby_mvc/views/table_view'
82
- #require 'ruby_mvc/views/ar_model_editor'
83
- #require 'ruby_mvc/views/ar_type_list'
84
- #require 'ruby_mvc/views/ar_type_editor'
85
- require 'ruby_mvc/views/web_view'
34
+ #require 'ruby_mvc/views/web_table_view'
@@ -1,7 +1,7 @@
1
1
  #--
2
2
  ######################################################################
3
3
  #
4
- # Copyright 2011 Andrew S. Townley
4
+ # Copyright 2011-2012 Andrew S. Townley
5
5
  #
6
6
  # Permission to use, copy, modify, and disribute this software for
7
7
  # any purpose with or without fee is hereby granted, provided that
@@ -17,8 +17,8 @@
17
17
  # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18
18
  # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
19
  #
20
- # File: ar_type_list.rb
21
- # Created: Mon 21 Nov 2011 15:57:27 GMT
20
+ # File: ar_form_view.rb
21
+ # Created: Sat 19 Nov 2011 11:26:37 GMT
22
22
  #
23
23
  #####################################################################
24
24
  #++
@@ -26,18 +26,15 @@
26
26
  module RubyMVC
27
27
  module Views
28
28
 
29
- class ActiveRecordTypeList < TableView
30
- def load(model, options = {}, &block)
31
- @entity_type = model
32
- super(model.find(options[:query] || :all), options, &block)
33
- end
29
+ # This class is responsible for building a form for the
30
+ # given ActiveRecord model
34
31
 
35
- def columns(model, options)
36
- cols = []
37
- @entity_type.attribute_names.each do |key|
38
- cols << { :key => key, :label => key.capitalize }
32
+ class ActiveRecordFormView < FormView
33
+ def initialize(model, &block)
34
+ super
35
+ signal_connect("form-submit") do |f, m|
36
+ m.save!
39
37
  end
40
- cols
41
38
  end
42
39
  end
43
40