glimmer-dsl-swt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +47 -0
  4. data/RUBY_VERSION +1 -0
  5. data/VERSION +1 -0
  6. data/bin/girb +10 -0
  7. data/bin/girb_runner.rb +13 -0
  8. data/bin/glimmer +5 -0
  9. data/icons/scaffold_app.icns +0 -0
  10. data/lib/ext/glimmer.rb +13 -0
  11. data/lib/ext/glimmer/config.rb +18 -0
  12. data/lib/glimmer-dsl-swt.rb +12 -0
  13. data/lib/glimmer/data_binding/list_selection_binding.rb +52 -0
  14. data/lib/glimmer/data_binding/model_binding.rb +248 -0
  15. data/lib/glimmer/data_binding/observable.rb +21 -0
  16. data/lib/glimmer/data_binding/observable_array.rb +107 -0
  17. data/lib/glimmer/data_binding/observable_model.rb +108 -0
  18. data/lib/glimmer/data_binding/observable_widget.rb +17 -0
  19. data/lib/glimmer/data_binding/observer.rb +124 -0
  20. data/lib/glimmer/data_binding/shine.rb +23 -0
  21. data/lib/glimmer/data_binding/table_items_binding.rb +56 -0
  22. data/lib/glimmer/data_binding/tree_items_binding.rb +71 -0
  23. data/lib/glimmer/data_binding/widget_binding.rb +33 -0
  24. data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
  25. data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
  26. data/lib/glimmer/dsl/swt/color_expression.rb +19 -0
  27. data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
  28. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
  29. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +39 -0
  30. data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
  31. data/lib/glimmer/dsl/swt/dialog_expression.rb +26 -0
  32. data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
  33. data/lib/glimmer/dsl/swt/dsl.rb +34 -0
  34. data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
  35. data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
  36. data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
  37. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
  38. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
  39. data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
  40. data/lib/glimmer/dsl/swt/message_box_expression.rb +29 -0
  41. data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
  42. data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
  43. data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
  44. data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
  45. data/lib/glimmer/dsl/swt/shell_expression.rb +25 -0
  46. data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
  47. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
  48. data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
  49. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
  50. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
  51. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
  52. data/lib/glimmer/dsl/swt/widget_expression.rb +35 -0
  53. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
  54. data/lib/glimmer/launcher.rb +196 -0
  55. data/lib/glimmer/package.rb +57 -0
  56. data/lib/glimmer/rake_task.rb +62 -0
  57. data/lib/glimmer/scaffold.rb +582 -0
  58. data/lib/glimmer/swt/color_proxy.rb +53 -0
  59. data/lib/glimmer/swt/display_proxy.rb +88 -0
  60. data/lib/glimmer/swt/font_proxy.rb +72 -0
  61. data/lib/glimmer/swt/layout_data_proxy.rb +84 -0
  62. data/lib/glimmer/swt/layout_proxy.rb +82 -0
  63. data/lib/glimmer/swt/menu_proxy.rb +101 -0
  64. data/lib/glimmer/swt/message_box_proxy.rb +48 -0
  65. data/lib/glimmer/swt/packages.rb +13 -0
  66. data/lib/glimmer/swt/shell_proxy.rb +152 -0
  67. data/lib/glimmer/swt/swt_proxy.rb +106 -0
  68. data/lib/glimmer/swt/tab_item_proxy.rb +65 -0
  69. data/lib/glimmer/swt/table_proxy.rb +150 -0
  70. data/lib/glimmer/swt/tree_proxy.rb +120 -0
  71. data/lib/glimmer/swt/widget_listener_proxy.rb +34 -0
  72. data/lib/glimmer/swt/widget_proxy.rb +489 -0
  73. data/lib/glimmer/ui/custom_shell.rb +45 -0
  74. data/lib/glimmer/ui/custom_widget.rb +244 -0
  75. data/lib/glimmer/util/proc_tracker.rb +16 -0
  76. data/vendor/swt/linux/swt.jar +0 -0
  77. data/vendor/swt/mac/swt.jar +0 -0
  78. data/vendor/swt/windows/swt.jar +0 -0
  79. metadata +307 -0
@@ -0,0 +1,53 @@
1
+ require 'glimmer/swt/swt_proxy'
2
+ require 'glimmer/swt/display_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Proxy for org.eclipse.swt.graphics.Color
7
+ #
8
+ # Invoking `#swt_color` returns the SWT color object wrapped by this proxy
9
+ #
10
+ # Follows the Proxy Design Pattern
11
+ class ColorProxy
12
+ include_package 'org.eclipse.swt.graphics'
13
+
14
+ # Initializes a proxy for an SWT Color object
15
+ #
16
+ # Takes a standard color single argument, rgba 3 args, or rgba 4 args
17
+ #
18
+ # A standard color is a string/symbol representing one of the
19
+ # SWT.COLOR_*** constants like SWT.COLOR_RED, but in underscored string
20
+ # format (e.g :color_red).
21
+ # Glimmer can also accept standard color names without the color_ prefix,
22
+ # and it will automatically figure out the SWT.COLOR_*** constant
23
+ # (e.g. :red)
24
+ #
25
+ # rgb is 3 arguments representing Red, Green, Blue numeric values
26
+ #
27
+ # rgba is 4 arguments representing Red, Green, Blue, and Alpha numeric values
28
+ #
29
+ def initialize(*args)
30
+ @args = args
31
+ end
32
+
33
+ def swt_color
34
+ unless @swt_color
35
+ case @args.size
36
+ when 1
37
+ if @args.first.is_a?(String) || @args.first.is_a?(Symbol)
38
+ standard_color = @args.first
39
+ standard_color = "color_#{standard_color}".to_sym unless standard_color.to_s.downcase.include?('color_')
40
+ @swt_color = DisplayProxy.instance.swt_display.getSystemColor(SWTProxy[standard_color])
41
+ else
42
+ @swt_color = @args.first
43
+ end
44
+ when 3..4
45
+ red, green, blue, alpha = @args
46
+ @swt_color = Color.new(DisplayProxy.instance.swt_display, *[red, green, blue, alpha].compact)
47
+ end
48
+ end
49
+ @swt_color
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,88 @@
1
+ require 'glimmer/swt/widget_listener_proxy'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ # Proxy for org.eclipse.swt.widgets.Display
6
+ #
7
+ # Maintains a singleton instance since SWT only supports
8
+ # a single active display at a time.
9
+ #
10
+ # Supports SWT Display's very useful asyncExec and syncExec methods
11
+ # to support proper multi-threaded manipulation of SWT UI objects
12
+ #
13
+ # Invoking `#swt_display` returns the SWT Display object wrapped by this proxy
14
+ #
15
+ # Follows the Proxy Design Pattern
16
+ class DisplayProxy
17
+ include_package 'org.eclipse.swt.widgets'
18
+
19
+ OBSERVED_MENU_ITEMS = ['about', 'preferences']
20
+
21
+ class << self
22
+ # Returns singleton instance
23
+ def instance(*args)
24
+ if @instance.nil? || @instance.swt_display.isDisposed
25
+ @instance = new(*args)
26
+ end
27
+ @instance
28
+ end
29
+ end
30
+
31
+ # SWT Display object wrapped
32
+ attr_reader :swt_display
33
+
34
+ def initialize(*args)
35
+ @swt_display = Display.new(*args)
36
+ end
37
+
38
+ def dispose
39
+ @swt_display.dispose
40
+ end
41
+
42
+ # Executes code block asynchronously with respect to SWT UI thread
43
+ def async_exec(&block)
44
+ @swt_display.asyncExec(&block)
45
+ end
46
+
47
+ # Executes code block synchronously with respect to SWT UI thread
48
+ def sync_exec(&block)
49
+ @swt_display.syncExec(&block)
50
+ end
51
+
52
+ def can_handle_observation_request?(observation_request)
53
+ observation_request = observation_request.to_s
54
+ if observation_request.start_with?('on_event_')
55
+ constant_name = observation_request.sub(/^on_event_/, '')
56
+ SWTProxy.has_constant?(constant_name)
57
+ elsif observation_request.start_with?('on_')
58
+ event_name = observation_request.sub(/^on_/, '')
59
+ OBSERVED_MENU_ITEMS.include?(event_name)
60
+ else
61
+ false
62
+ end
63
+ end
64
+
65
+ def handle_observation_request(observation_request, &block)
66
+ if observation_request.start_with?('on_event_')
67
+ constant_name = observation_request.sub(/^on_event_/, '')
68
+ add_swt_event_listener(constant_name, &block)
69
+ elsif observation_request.start_with?('on_')
70
+ event_name = observation_request.sub(/^on_/, '')
71
+ if OBSERVED_MENU_ITEMS.include?(event_name)
72
+ if OS.mac?
73
+ system_menu = swt_display.getSystemMenu
74
+ menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
75
+ menu_item.addListener(SWTProxy[:Selection], &block)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def add_swt_event_listener(swt_constant, &block)
82
+ event_type = SWTProxy[swt_constant]
83
+ @swt_display.addFilter(event_type, &block)
84
+ #WidgetListenerProxy.new(@swt_display.getListeners(event_type).last)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,72 @@
1
+ require 'glimmer/error'
2
+ require 'glimmer/swt/swt_proxy'
3
+ require 'glimmer/swt/display_proxy'
4
+
5
+ module Glimmer
6
+ module SWT
7
+ # Proxy for org.eclipse.swt.graphics.Font
8
+ #
9
+ # This class is meant to be used with WidgetProxy to manipulate
10
+ # an SWT widget font.
11
+ #
12
+ # It is not meant to create new SWT fonts form scratch without
13
+ # a widget proxy.
14
+ #
15
+ # Invoking `#swt_font` returns the SWT Font object wrapped by this proxy
16
+ #
17
+ # Follows the Proxy Design Pattern
18
+ class FontProxy
19
+ ERROR_INVALID_FONT_STYLE = " is an invalid font style! Valid values are :normal, :bold, and :italic"
20
+ FONT_STYLES = [:normal, :bold, :italic]
21
+
22
+ include_package 'org.eclipse.swt.graphics'
23
+
24
+ attr_reader :widget_proxy, :swt_font
25
+
26
+ # Builds a new font proxy from passed in widget_proxy and font_properties hash,
27
+ #
28
+ # It begins with existing SWT widget font and amends it with font properties.
29
+ #
30
+ # Font properties consist of: :name, :height, and :style (one needed minimum)
31
+ #
32
+ # Style (:style value) can only be one of FontProxy::FONT_STYLES values:
33
+ # that is :normal, :bold, or :italic
34
+ def initialize(widget_proxy, font_properties)
35
+ @widget_proxy = widget_proxy
36
+ detect_invalid_font_property(font_properties)
37
+ font_properties[:style] = SWTProxy[*font_properties[:style]]
38
+ font_data_args = [:name, :height, :style].map do |font_property_name|
39
+ font_properties[font_property_name] || send(font_property_name)
40
+ end
41
+ font_datum = FontData.new(*font_data_args)
42
+ @swt_font = Font.new(DisplayProxy.instance.swt_display, font_datum)
43
+ end
44
+
45
+ def name
46
+ font_datum.getName
47
+ end
48
+
49
+ def height
50
+ font_datum.getHeight
51
+ end
52
+
53
+ def style
54
+ font_datum.getStyle
55
+ end
56
+
57
+ private
58
+
59
+ def font_datum
60
+ @font_datum ||= @widget_proxy.swt_widget.getFont.getFontData[0]
61
+ end
62
+
63
+ def detect_invalid_font_property(font_properties)
64
+ [font_properties[:style]].flatten.select do |style|
65
+ style.is_a?(Symbol) || style.is_a?(String)
66
+ end.each do |style|
67
+ raise Error, style.to_s + ERROR_INVALID_FONT_STYLE if !FONT_STYLES.include?(style.to_sym)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,84 @@
1
+ require 'glimmer'
2
+ require 'glimmer/swt/swt_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Generic proxy for all SWT layout data objects, such as GridData & RowData
7
+ #
8
+ # This class is meant to be used with an existing WidgetProxy
9
+ # as it figures out the right SWT layout data class name
10
+ # by convention from the parent SWT widget layout class name
11
+ #
12
+ # The convention is:
13
+ # - Start with the parent widget layout package/class name (e.g. org.eclipse.swt.layout.RowLayout)
14
+ # - Replace the word "Layout" with "Data" in the class name
15
+ #
16
+ # Examples of figuring out SWT layout data class:
17
+ # - org.eclipse.swt.layout.RowData for org.eclipse.swt.layout.RowLayout
18
+ # - org.eclipse.swt.layout.GridData for org.eclipse.swt.layout.GridLayout
19
+ #
20
+ # Follows the Proxy Design Pattern
21
+ class LayoutDataProxy
22
+ include_package 'org.eclipse.swt.layout'
23
+
24
+ attr_reader :widget_proxy
25
+ attr_reader :swt_layout_data
26
+
27
+ # Inititalizes with owning widget proxy and layout data arguments
28
+ def initialize(widget_proxy, args)
29
+ @widget_proxy = widget_proxy
30
+ args = SWTProxy.constantify_args(args)
31
+ begin
32
+ @swt_layout_data = swt_layout_data_class.new(*args)
33
+ rescue => e
34
+ Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
35
+ @swt_layout_data = args.first if args.count == 1
36
+ end
37
+ @widget_proxy.swt_widget.setLayoutData(@swt_layout_data)
38
+ end
39
+
40
+ # This figures out the right SWT layout data class name
41
+ # by convention from the parent SWT widget layout class name
42
+ #
43
+ # Supports layout data classes in and out of basic SWT library
44
+ #
45
+ # The convention is:
46
+ # - Start with the parent widget layout package/class name (e.g. org.eclipse.swt.layout.RowLayout)
47
+ # - Replace the word "Layout" with "Data" in the class name
48
+ #
49
+ # Examples of figuring out SWT layout data class:
50
+ # - org.eclipse.swt.layout.RowData for org.eclipse.swt.layout.RowLayout
51
+ # - org.eclipse.swt.layout.GridData for org.eclipse.swt.layout.GridLayout
52
+ #
53
+ def swt_layout_data_class
54
+ parent_layout_class_name = @widget_proxy.swt_widget.getParent.getLayout.class.name
55
+ layout_data_class_name = parent_layout_class_name.sub(/Layout$/, 'Data')
56
+ eval(layout_data_class_name)
57
+ end
58
+
59
+ def has_attribute?(attribute_name, *args)
60
+ @swt_layout_data.respond_to?(attribute_setter(attribute_name), args)
61
+ end
62
+
63
+ def set_attribute(attribute_name, *args)
64
+ args = SWTProxy.constantify_args(args)
65
+ if args.first != @swt_layout_data.send(attribute_getter(attribute_name))
66
+ @swt_layout_data.send(attribute_setter(attribute_name), *args)
67
+ @widget_proxy.swt_widget.getShell.pack
68
+ end
69
+ end
70
+
71
+ def get_attribute(attribute_name)
72
+ @swt_layout_data.send(attribute_getter(attribute_name))
73
+ end
74
+
75
+ def attribute_setter(attribute_name)
76
+ "#{attribute_name.to_s.camelcase(:lower)}="
77
+ end
78
+
79
+ def attribute_getter(attribute_name)
80
+ "#{attribute_name.to_s.camelcase(:lower)}"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,82 @@
1
+ require 'glimmer'
2
+ require 'glimmer/swt/swt_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Proxy for org.eclipse.swt.widgets.Layout
7
+ #
8
+ # This is meant to be used with a WidgetProxy where it will
9
+ # set the layout in the SWT widget upon instantiation.
10
+ #
11
+ # Follows the Proxy Design Pattern
12
+ class LayoutProxy
13
+ attr_reader :widget_proxy, :swt_layout
14
+
15
+ class << self
16
+ include_package 'org.eclipse.swt.layout'
17
+ include_package 'org.eclipse.swt.widgets'
18
+
19
+ def layout_exists?(underscored_layout_name)
20
+ begin
21
+ swt_layout_class_for(underscored_layout_name)
22
+ true
23
+ rescue NameError => e
24
+ false
25
+ end
26
+ end
27
+
28
+ # This supports layouts in and out of basic SWT library
29
+ def swt_layout_class_for(underscored_layout_name)
30
+ swt_layout_name = underscored_layout_name.camelcase(:upper)
31
+ swt_layout_class = eval(swt_layout_name)
32
+ unless swt_layout_class.ancestors.include?(Layout)
33
+ raise NameError, "Class #{swt_layout_class} matching #{underscored_layout_name} is not a subclass of org.eclipse.swt.widgets.Layout"
34
+ end
35
+ swt_layout_class
36
+ rescue => e
37
+ Glimmer::Config.logger&.debug e.message
38
+ # Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
39
+ raise e
40
+ end
41
+ end
42
+
43
+ def initialize(underscored_layout_name, widget_proxy, args)
44
+ @underscored_layout_name = underscored_layout_name
45
+ @widget_proxy = widget_proxy
46
+ args = SWTProxy.constantify_args(args)
47
+ @swt_layout = self.class.swt_layout_class_for(underscored_layout_name).new(*args)
48
+ @widget_proxy.swt_widget.setLayout(@swt_layout)
49
+ end
50
+
51
+ def has_attribute?(attribute_name, *args)
52
+ @swt_layout.respond_to?(attribute_setter(attribute_name), args)
53
+ end
54
+
55
+ def set_attribute(attribute_name, *args)
56
+ apply_property_type_converters(attribute_name, args)
57
+ if args.first != @swt_layout.send(attribute_getter(attribute_name))
58
+ @swt_layout.send(attribute_setter(attribute_name), *args)
59
+ @widget_proxy.swt_widget.getShell.pack
60
+ end
61
+ end
62
+
63
+ def get_attribute(attribute_name)
64
+ @swt_layout.send(attribute_getter(attribute_name))
65
+ end
66
+
67
+ def apply_property_type_converters(attribute_name, args)
68
+ if args.count == 1 && SWTProxy.has_constant?(args.first)
69
+ args[0] = SWTProxy.constant(args.first)
70
+ end
71
+ end
72
+
73
+ def attribute_setter(attribute_name)
74
+ "#{attribute_name.to_s.camelcase(:lower)}="
75
+ end
76
+
77
+ def attribute_getter(attribute_name)
78
+ "#{attribute_name.to_s.camelcase(:lower)}"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,101 @@
1
+ require 'glimmer/swt/widget_proxy'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ # Proxy for org.eclipse.swt.widgets.Menu
6
+ #
7
+ # Functions differently from other widget proxies.
8
+ #
9
+ # Glimmer automatically detects if this is a drop down menu
10
+ # or pop up menu from its parent if no SWT style is passed in.
11
+ #
12
+ # There are 3 possibilities:
13
+ # - SWT :bar style is passed in: Menu Bar
14
+ # - Parent is ShellProxy: Pop Up Menu (having style :pop_up)
15
+ # - Parent is another Menu: Drop Down Menu (having style :drop_down)
16
+ #
17
+ # In order to get the SWT Menu object, one must call `#swt_widget`.
18
+ #
19
+ # In the case of a Drop Down menu, this automatically creates an
20
+ # SWT MenuItem object with style :cascade
21
+ #
22
+ # In order to retrieve the menu item widget proxy, one must call `#menu_item_proxy`
23
+ #
24
+ # Follows the Proxy Design Pattern
25
+ class MenuProxy < WidgetProxy
26
+ include_package 'org.eclipse.swt.widgets'
27
+
28
+ attr_reader :menu_item_proxy, :swt_menu_item, :menu_parent
29
+
30
+ def initialize(parent, args)
31
+ index = args.delete(args.last) if args.last.is_a?(Numeric)
32
+ styles = args.map(&:to_sym)
33
+ if !styles.include?(:bar) && !parent.swt_widget.is_a?(Menu)
34
+ styles = styles.unshift(:pop_up)
35
+ end
36
+
37
+ swt_widget_class = self.class.swt_widget_class_for('menu')
38
+ if parent.swt_widget.is_a?(Menu)
39
+ @menu_item_proxy = SWT::WidgetProxy.new('menu_item', parent, [:cascade] + [index].compact)
40
+ @swt_menu_item = @menu_item_proxy.swt_widget
41
+ @swt_widget = swt_widget_class.new(@menu_item_proxy.swt_widget)
42
+ @swt_menu_item.setMenu(swt_widget)
43
+ elsif parent.swt_widget.is_a?(Shell)
44
+ @swt_widget = swt_widget_class.new(parent.swt_widget, style('menu', styles))
45
+ else
46
+ @swt_widget = swt_widget_class.new(parent.swt_widget)
47
+ end
48
+ DEFAULT_INITIALIZERS['menu']&.call(swt_widget)
49
+
50
+ if styles.include?(:bar)
51
+ parent.swt_widget.setMenuBar(swt_widget)
52
+ elsif styles.include?(:pop_up)
53
+ parent.swt_widget.setMenu(swt_widget)
54
+ end
55
+ end
56
+
57
+ def has_attribute?(attribute_name, *args)
58
+ if attribute_name.to_s == "text"
59
+ true
60
+ else
61
+ super(attribute_name, *args)
62
+ end
63
+ end
64
+
65
+ def set_attribute(attribute_name, *args)
66
+ attribute_name
67
+ if attribute_name.to_s == "text"
68
+ text_value = args[0]
69
+ @swt_menu_item.setText text_value
70
+ else
71
+ super(attribute_name, *args)
72
+ end
73
+ end
74
+
75
+ def get_attribute(attribute_name)
76
+ if attribute_name.to_s == "text"
77
+ @swt_menu_item.getText
78
+ else
79
+ super(attribute_name)
80
+ end
81
+ end
82
+
83
+ def can_handle_observation_request?(observation_request, super_only: false)
84
+ super_result = super(observation_request)
85
+ if observation_request.start_with?('on_') && !super_result && !super_only
86
+ return menu_item_proxy.can_handle_observation_request?(observation_request)
87
+ else
88
+ super_result
89
+ end
90
+ end
91
+
92
+ def handle_observation_request(observation_request, &block)
93
+ if can_handle_observation_request?(observation_request, super_only: true)
94
+ super
95
+ else
96
+ menu_item_proxy.handle_observation_request(observation_request, &block)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end