ruby_mvc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -23,35 +23,103 @@
23
23
  #####################################################################
24
24
  #++
25
25
 
26
- module ShoesMVC
26
+ module RubyMVC
27
27
  module Models
28
28
 
29
- # This class implements the TableModel interface based on
30
- # the data being stored in an array. The elements in the
31
- # array must either be a Hash, or they must respond to the
32
- # [] accessors for retrieving elements by key and implement
33
- # a #keys method for indicating the properties in each row
34
- # instance.
29
+ # This class provides an adapter to expose an array of
30
+ # hashes or anything else that responds to the #keys, #[]
31
+ # and #[]= methods as a TableModel instance.
32
+ #
33
+ # Note that the keys of the objects in the array will be
34
+ # requested as symbols and not as any other object type.
35
35
 
36
- class ArrayTableModel < TableModel
37
- def initialize(data)
36
+ class HashArrayTableModel < TableModel
37
+ def initialize(data, options = {})
38
+ raise ArgumentError, "argument not an Array" if !data.is_a? Array
39
+ super(options)
40
+
41
+ @options = options
38
42
  @data = data
39
43
  end
40
44
 
45
+ def create_rows(count = 1)
46
+ if f = @options[:row_factory]
47
+ f.call(count)
48
+ else
49
+ r = []
50
+ t = @options[:row_template] || @data.last
51
+ count.times { r << t.clone }
52
+ r
53
+ end
54
+ end
55
+
56
+ def insert_row(index, row)
57
+ @data.insert(index, row)
58
+ super(index, Model.adapt(row, @options))
59
+ end
60
+
61
+ def insert_rows(index, rows)
62
+ @data.insert(index, *rows)
63
+ super(index, rows.collect { |r| Model.adapt(r, @options) })
64
+ end
65
+
66
+ def remove_row(index)
67
+ row = Model.adapt(@data.delete_at(index), @options)
68
+ signal_emit("rows-removed", self, index, [ row ])
69
+ row
70
+ end
71
+
72
+ def remove_rows(index, count)
73
+ rows = []
74
+ count.times do
75
+ rows << Model.adapt(@data.delete_at(index), @options)
76
+ end
77
+ signal_emit("rows-removed", self, index, rows)
78
+ rows
79
+ end
80
+
81
+ def update_row(index, row)
82
+ @data[index] = row
83
+ super(index, Model.adapt(row, @options))
84
+ end
85
+
86
+ # The keys used will come from the first element in the
87
+ # array or be empty if the array is empty.
88
+
41
89
  def keys
42
- if @data && @data.size > 0
43
- @data.keys
90
+ if @data.size > 0
91
+ @data.first.keys
44
92
  else
45
93
  {}
46
94
  end
47
95
  end
48
96
 
97
+ def value_for(row, key)
98
+ @data[row][key.to_sym]
99
+ end
100
+
101
+ def [](row)
102
+ @data[row]
103
+ end
104
+
105
+ # Iterates over each of the elements in the array and
106
+ # provides a Model instance to the caller based on the
107
+ # keys contained in the object itself.
108
+
49
109
  def each(&block)
50
- @data.each(&block)
110
+ return if !block
111
+
112
+ @data.each do |x|
113
+ block.call(Model.adapt(x, @options))
114
+ end
51
115
  end
52
116
 
53
117
  def each_with_index(&block)
54
- @data.each_with_index(&block)
118
+ return if !block
119
+
120
+ @data.each_with_index do |x, i|
121
+ block.call(Model.adapt(x, @options), i)
122
+ end
55
123
  end
56
124
  end
57
125
 
@@ -23,7 +23,7 @@
23
23
  #####################################################################
24
24
  #++
25
25
 
26
- module ShoesMVC
26
+ module RubyMVC
27
27
  module Models
28
28
 
29
29
  class KeyedArrayTableModel < TableModel
@@ -0,0 +1,129 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011 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: model.rb
21
+ # Created: Fri 30 Dec 2011 12:46:32 CET
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Models
28
+
29
+ # This class defines the generic API for models in RubyMVC.
30
+ # Models expose key/value pairs to other parts of the
31
+ # system, but they are more than simple Hash instances
32
+ # because not all properties of a model are always editable.
33
+
34
+ class Model
35
+ include Toolkit::SignalHandler
36
+ extend Toolkit::SignalHandler::ClassMethods
37
+
38
+ # this signal is emitted when any property is changed on
39
+ # the model. The arguments are the sender, the old and
40
+ # the new values
41
+
42
+ signal "property-changed"
43
+
44
+ # This method is used to use the Model class to adapt any
45
+ # object that responds to the #keys, #size, #[] and #[]=
46
+ # methods
47
+
48
+ def self.adapt(obj, options = {})
49
+ return obj if obj.is_a? Model
50
+ self.new(options.merge({:data => obj}))
51
+ end
52
+
53
+ # The base model is backed by a simple Hash, and supports
54
+ # specifying the following options for defining which
55
+ # properties are editable or not.
56
+
57
+ def initialize(options = {})
58
+ @data = options.delete(:data) || {}
59
+ @options = options
60
+ end
61
+
62
+ # This method is used to provide the property keys of the
63
+ # model as symbols.
64
+
65
+ def keys
66
+ @data.keys.sort.collect { |k| k.to_sym }
67
+ end
68
+
69
+ # This method is used to retrieve the property key and the
70
+ # display label for the key to be used by views when
71
+ # displaying model data.
72
+
73
+ def labels
74
+ @labels = {}
75
+ self.keys.collect do |k|
76
+ x = { :key => k.to_sym, :label => k.to_s.capitalize }
77
+ @labels[x[:key]] = x[:label]
78
+ x
79
+ end
80
+ end
81
+
82
+ # This method is used to check whether a property key is
83
+ # editable or not
84
+
85
+ def is_editable?(key)
86
+ (@options[:editable] || {})[key.to_sym] || true
87
+ end
88
+
89
+ def [](key)
90
+ @data[key.to_sym]
91
+ end
92
+
93
+ def []=(key, val)
94
+ k = key.to_sym
95
+ old = @data[k]
96
+ @data[k] = val
97
+
98
+ if old != val
99
+ signal_emit("property-changed", self, k, old, val)
100
+ end
101
+ end
102
+
103
+ def size
104
+ @data.size
105
+ end
106
+
107
+ # This method is used to iterate over the properties of
108
+ # the model. For each property, the key, label and value
109
+ # are provide as arguments to the block
110
+
111
+ def each_label(&block)
112
+ labels.each do |l|
113
+ block.call((k = l[:key]), l[:label], @data[k])
114
+ end
115
+ end
116
+
117
+ # This method is used to retrieve the label for the
118
+ # specified model key.
119
+
120
+ def label_for(key)
121
+ if !@labels
122
+ labels
123
+ end
124
+ @labels[key.to_sym]
125
+ end
126
+ end
127
+
128
+ end
129
+ end
@@ -23,19 +23,116 @@
23
23
  #####################################################################
24
24
  #++
25
25
 
26
- module ShoesMVC
26
+ module RubyMVC
27
27
  module Models
28
28
 
29
- # This class defines the behavior of a base TableModel API
30
- # that is used by the TableView class. The model represents
31
- # an ordered set of data rows which are "square" in that
32
- # they are expected to all have the same number of columns.
33
- #
34
- # Logically, each of the elements in the table model is a
35
- # row instance that provides keyed property access to the
36
- # data in the model based on the [] method.
29
+ # The TableModel class expands the concepts of the Model
30
+ # class to a number of related rows with the same properties
31
+ # defined for the model.
37
32
 
38
- class TableModel
33
+ class TableModel < Model
34
+ # This signal is triggered when contiguous rows are
35
+ # inserted into the model. The arguments are the sender
36
+ # model, the insertion index and the row models that were
37
+ # inserted.
38
+
39
+ signal "rows-inserted"
40
+
41
+ # This signal is triggered when contiguous rows are
42
+ # removed from the model. The arguments are the index at
43
+ # which the removal took place and the row models that
44
+ # were removed from the model.
45
+
46
+ signal "rows-removed"
47
+
48
+ # This signal is triggered when an existing row has been
49
+ # changed. The arguments are the sender, the index and
50
+ # the changed row model
51
+
52
+ signal "row-changed"
53
+
54
+ # This method is used to create a number of row data
55
+ # elements that will be inserted into the model at the
56
+ # specified location using the #insert_row or #insert_rows
57
+ # method.
58
+ #
59
+ # The result is an array of row data instances in whatever
60
+ # format is deemed suitable for the model instance to
61
+ # create.
62
+
63
+ def create_rows(count = 1)
64
+ end
65
+
66
+ # This method is used to insert a single row into the
67
+ # model at the given row index.
68
+
69
+ def insert_row(index, row)
70
+ signal_emit("rows-inserted", self, index, [ row ])
71
+ end
72
+
73
+ # This method is used to insert an array of row objects
74
+ # into the model at the specified index
75
+
76
+ def insert_rows(index, rows)
77
+ signal_emit("rows-inserted", self, index, rows)
78
+ end
79
+
80
+ # This method is used remove a single row from the model
81
+ # and return a reference to the row model removed to the
82
+ # caller.
83
+ #
84
+ # Note, the derived classes are responsible for emitting
85
+ # the appropriate signal since the data access is opaque
86
+ # to the base class.
87
+
88
+ def remove_row(index)
89
+ end
90
+
91
+ # This method is used remove multiple rows from the model
92
+ # and return a reference to the row models removed to the
93
+ # caller.
94
+ #
95
+ # Note, the derived classes are responsible for emitting
96
+ # the appropriate signal since the data access is opaque
97
+ # to the base class.
98
+
99
+ def remove_rows(index, count)
100
+ end
101
+
102
+ # This method is used to update the specified row in the
103
+ # model and ensure that the appropriate notifications for
104
+ # all linked views are sent.
105
+
106
+ def update_row(index, row)
107
+ signal_emit("row-changed", index, row)
108
+ end
109
+
110
+ # This method will iterate over each of the rows and
111
+ # provide the caller with a reference to the row instance,
112
+ # which is also conformant with the Model API
113
+
114
+ def each(&block)
115
+ end
116
+
117
+ # This method will iterate over each of rows and provide
118
+ # the caller with a reference to the row instance as a
119
+ # model and the index of the row.
120
+
121
+ def each_with_index(&block)
122
+ end
123
+
124
+ # This method allows direct access into the model rows, in
125
+ # row-major order for the specified, zero-based index and
126
+ # property key
127
+
128
+ def value_for(row, key)
129
+ end
130
+
131
+ # This method is used to retrieve the model instance for
132
+ # the given row index
133
+
134
+ def [](idx)
135
+ end
39
136
  end
40
137
 
41
138
  end
@@ -0,0 +1,140 @@
1
+ #--
2
+ ######################################################################
3
+ #
4
+ # Copyright 2011 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: view_model_template.rb
21
+ # Created: Mon 12 Dec 2011 06:30:57 CST
22
+ #
23
+ #####################################################################
24
+ #++
25
+
26
+ module RubyMVC
27
+ module Models
28
+
29
+ # This class provides a proxy for Model instances that
30
+ # allows them to control the visibility of which properties
31
+ # are exposed for a given view. ViewModelTemplate instances can
32
+ # be reused across view instances where the same properties
33
+ # are to be exposed.
34
+ #
35
+ # The ViewModelTemplate class implements the same interface as
36
+ # Model instances so that they can be used as drop-in
37
+ # replacements everywhere a model instance can be used.
38
+ #
39
+ # The key difference is that the ViewModelTemplate exists outside
40
+ # of any particular model instances, allowing the same view
41
+ # binding to work for numerous concrete model instances,
42
+ # effectively speifying the template through which the model
43
+ # may be accessed.
44
+
45
+ class ViewModelTemplate
46
+ attr_accessor :title
47
+
48
+ # When the ViewModelTemplate is initialized, it requires a set
49
+ # of options and/or an optional initializer block that is
50
+ # executed within the scope of the newly created instance.
51
+
52
+ def initialize(options = {}, &block)
53
+ @options = options
54
+ @labels = []
55
+ @options[:editable] ||= {}
56
+ @options[:properties] ||= []
57
+ self.instance_eval(&block) if block
58
+ end
59
+
60
+ def keys
61
+ @options[:properties]
62
+ end
63
+
64
+ # Implement the Model#labels method in terms of the
65
+ # template definition
66
+
67
+ def labels
68
+ @labels
69
+ end
70
+
71
+ # Implement the Model#is_editable? method in terms of the
72
+ # template definition. If the template doesn't further
73
+ # restrict the behavior, the model's definition is used
74
+ # instead.
75
+
76
+ def is_editable?(key)
77
+ k = key.to_sym
78
+ if @options[:editable].has_key? k
79
+ @options[:editable][k]
80
+ else
81
+ true
82
+ end
83
+ end
84
+
85
+ # This method is used to mark a property key editable or
86
+ # not through the view. This method does not impact the
87
+ # editability of the underlying model
88
+
89
+ def editable(key, val = true)
90
+ @options[:editable][key.to_sym] = val
91
+ end
92
+
93
+ # This method is used to mark a property visible or not
94
+ # through the view.
95
+
96
+ def property(key, options = {})
97
+ puts "options: #{options.inspect}"
98
+ key = key.to_sym
99
+
100
+ if false == options[:show]
101
+ show = false
102
+ else
103
+ show = true
104
+ end
105
+
106
+ editable(key, false) if false == options[:editable]
107
+
108
+ if show && !@options[:properties].include?(key)
109
+ @options[:properties] << key
110
+ l = options[:alias] || key.to_s.capitalize
111
+ @labels << options.merge({ :key => key, :label => l })
112
+ elsif !show
113
+ @options[:properties].delete(key)
114
+ @labels.delete_if do |k|
115
+ k[:key] == key
116
+ end
117
+ end
118
+ end
119
+
120
+ # This method is used to apply the template to a specific,
121
+ # concrete model instance, creating a clone of the
122
+ # template in the process so that multiple different
123
+ # models can be used with the same template definition.
124
+
125
+ def apply(model)
126
+ @model = model
127
+ self.clone
128
+ end
129
+
130
+ def method_missing(m, *args, &block)
131
+ if @model
132
+ @model.send(m, *args, &block)
133
+ else
134
+ super
135
+ end
136
+ end
137
+ end
138
+
139
+ end
140
+ end