intelitiva-rugui 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/Changelog +54 -0
  2. data/LICENSE +165 -0
  3. data/README +67 -0
  4. data/Rakefile +11 -0
  5. data/bin/rugui +16 -0
  6. data/lib/rugui/base_controller.rb +194 -0
  7. data/lib/rugui/base_model.rb +22 -0
  8. data/lib/rugui/base_object.rb +73 -0
  9. data/lib/rugui/base_view.rb +302 -0
  10. data/lib/rugui/base_view_helper.rb +23 -0
  11. data/lib/rugui/configuration.rb +136 -0
  12. data/lib/rugui/framework_adapters/GTK.rb +233 -0
  13. data/lib/rugui/framework_adapters/Qt4.rb +171 -0
  14. data/lib/rugui/framework_adapters/base_framework_adapter.rb +90 -0
  15. data/lib/rugui/framework_adapters/framework_adapter_support.rb +35 -0
  16. data/lib/rugui/gem_builder.rb +21 -0
  17. data/lib/rugui/gem_dependency.rb +282 -0
  18. data/lib/rugui/initialize_hooks.rb +36 -0
  19. data/lib/rugui/initializer.rb +162 -0
  20. data/lib/rugui/log_support.rb +118 -0
  21. data/lib/rugui/observable_property_proxy.rb +73 -0
  22. data/lib/rugui/observable_property_support.rb +251 -0
  23. data/lib/rugui/plugin/loader.rb +77 -0
  24. data/lib/rugui/property_observer.rb +58 -0
  25. data/lib/rugui/signal_support.rb +57 -0
  26. data/lib/rugui/tasks/gems_application.rake +71 -0
  27. data/lib/rugui/tasks/rugui.rb +8 -0
  28. data/lib/rugui/tasks/rugui_framework.rb +4 -0
  29. data/lib/rugui/tasks/runner_application.rake +4 -0
  30. data/lib/rugui/tasks/spec_application.rake +64 -0
  31. data/lib/rugui/tasks/spec_framework.rake +27 -0
  32. data/lib/rugui/tasks/test_application.rake +77 -0
  33. data/lib/rugui/vendor_gem_source_index.rb +140 -0
  34. data/lib/rugui/version.rb +9 -0
  35. data/lib/rugui.rb +37 -0
  36. data/rugui_generators/controller/USAGE +1 -0
  37. data/rugui_generators/controller/controller_generator.rb +35 -0
  38. data/rugui_generators/controller/templates/controller.erb +3 -0
  39. data/rugui_generators/generators_support.rb +75 -0
  40. data/rugui_generators/model/USAGE +1 -0
  41. data/rugui_generators/model/model_generator.rb +35 -0
  42. data/rugui_generators/model/templates/model.erb +3 -0
  43. data/rugui_generators/pack/USAGE +1 -0
  44. data/rugui_generators/pack/pack_generator.rb +40 -0
  45. data/rugui_generators/pack/templates/README +3 -0
  46. data/rugui_generators/rugui/USAGE +1 -0
  47. data/rugui_generators/rugui/rugui_generator.rb +163 -0
  48. data/rugui_generators/rugui/templates/GTK/application_controller.rb +4 -0
  49. data/rugui_generators/rugui/templates/GTK/application_view.rb +4 -0
  50. data/rugui_generators/rugui/templates/GTK/application_view_helper.rb +4 -0
  51. data/rugui_generators/rugui/templates/GTK/environment.rb +39 -0
  52. data/rugui_generators/rugui/templates/GTK/main.rc +23 -0
  53. data/rugui_generators/rugui/templates/GTK/main_controller.rb +17 -0
  54. data/rugui_generators/rugui/templates/GTK/main_view.glade +33 -0
  55. data/rugui_generators/rugui/templates/GTK/main_view.rb +10 -0
  56. data/rugui_generators/rugui/templates/GTK/main_view_helper.rb +3 -0
  57. data/rugui_generators/rugui/templates/Qt4/application_controller.rb +4 -0
  58. data/rugui_generators/rugui/templates/Qt4/application_view.rb +4 -0
  59. data/rugui_generators/rugui/templates/Qt4/application_view_helper.rb +4 -0
  60. data/rugui_generators/rugui/templates/Qt4/environment.rb +39 -0
  61. data/rugui_generators/rugui/templates/Qt4/main_controller.rb +13 -0
  62. data/rugui_generators/rugui/templates/Qt4/main_view.rb +10 -0
  63. data/rugui_generators/rugui/templates/Qt4/main_view.ui +37 -0
  64. data/rugui_generators/rugui/templates/Qt4/main_view_helper.rb +3 -0
  65. data/rugui_generators/rugui/templates/README +3 -0
  66. data/rugui_generators/rugui/templates/Rakefile +7 -0
  67. data/rugui_generators/rugui/templates/boot.rb +81 -0
  68. data/rugui_generators/rugui/templates/development.rb.sample +21 -0
  69. data/rugui_generators/rugui/templates/main.rb +11 -0
  70. data/rugui_generators/rugui/templates/main_executable.bat.erb +8 -0
  71. data/rugui_generators/rugui/templates/main_executable.erb +17 -0
  72. data/rugui_generators/rugui/templates/production.rb.sample +21 -0
  73. data/rugui_generators/rugui/templates/rcov.opts +1 -0
  74. data/rugui_generators/rugui/templates/spec.opts +4 -0
  75. data/rugui_generators/rugui/templates/spec_helper.rb +12 -0
  76. data/rugui_generators/rugui/templates/test.rb.sample +21 -0
  77. data/rugui_generators/rugui/templates/test_helper.rb +12 -0
  78. data/rugui_generators/view/USAGE +1 -0
  79. data/rugui_generators/view/templates/toplevels/about_dialog.glade +32 -0
  80. data/rugui_generators/view/templates/toplevels/assistant.glade +30 -0
  81. data/rugui_generators/view/templates/toplevels/color_selection_dialog.glade +60 -0
  82. data/rugui_generators/view/templates/toplevels/dialog_box.glade +35 -0
  83. data/rugui_generators/view/templates/toplevels/file_chooser_dialog.glade +35 -0
  84. data/rugui_generators/view/templates/toplevels/font_selection_dialog.glade +58 -0
  85. data/rugui_generators/view/templates/toplevels/input_dialog.glade +35 -0
  86. data/rugui_generators/view/templates/toplevels/message_dialog.glade +35 -0
  87. data/rugui_generators/view/templates/toplevels/recent_chooser_dialog.glade +33 -0
  88. data/rugui_generators/view/templates/toplevels/window.glade +11 -0
  89. data/rugui_generators/view/templates/view.erb +11 -0
  90. data/rugui_generators/view/templates/view.glade +4 -0
  91. data/rugui_generators/view/templates/view.ui +18 -0
  92. data/rugui_generators/view/templates/view_helper.erb +3 -0
  93. data/rugui_generators/view/view_generator.rb +36 -0
  94. data/script/console +10 -0
  95. data/script/destroy +14 -0
  96. data/script/generate +14 -0
  97. data/spec/framework/base_controller_spec.rb +48 -0
  98. data/spec/framework/base_model_spec.rb +13 -0
  99. data/spec/framework/base_view_helper_spec.rb +13 -0
  100. data/spec/framework/base_view_spec.rb +92 -0
  101. data/spec/framework/log_support_spec.rb +16 -0
  102. data/spec/framework/observable_property_proxy_spec.rb +67 -0
  103. data/spec/framework/observable_property_support_spec.rb +283 -0
  104. data/spec/framework/property_observer_spec.rb +88 -0
  105. data/spec/helpers/controllers.rb +29 -0
  106. data/spec/helpers/initialize_hooks_helper.rb +18 -0
  107. data/spec/helpers/models.rb +9 -0
  108. data/spec/helpers/observables.rb +210 -0
  109. data/spec/helpers/view_helpers.rb +9 -0
  110. data/spec/helpers/views.rb +72 -0
  111. data/spec/rcov.opts +1 -0
  112. data/spec/resource_files/my_other_view.glade +46 -0
  113. data/spec/resource_files/my_view.glade +46 -0
  114. data/spec/spec.opts +4 -0
  115. data/spec/spec_helper.rb +15 -0
  116. metadata +211 -0
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), "../generators_support")
2
+
3
+ class ViewGenerator < RubiGen::Base
4
+ include GeneratorsSupport
5
+
6
+ default_options :author => nil
7
+
8
+ attr_reader :name
9
+
10
+ def initialize(runtime_args, runtime_options = {})
11
+ @uses_builder = true
12
+ super
13
+ usage if args.empty?
14
+ @name = args.shift
15
+ extract_options
16
+ end
17
+
18
+ def manifest
19
+ record do |m|
20
+ build_view_templates(m)
21
+ end
22
+ end
23
+
24
+ protected
25
+ def banner
26
+ <<-EOS
27
+ Creates a RuGUI view with its resources.
28
+
29
+ USAGE: script/generate view YOUR_VIEW_NAME [options]
30
+ EOS
31
+ end
32
+
33
+ def add_options!(opts)
34
+ view_add_options!(opts)
35
+ end
36
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/rugui-newgem.rb'}"
9
+ puts "Loading rugui-newgem gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,48 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'controllers')
4
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'views')
5
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'models')
6
+
7
+ describe RuGUI::BaseController do
8
+ before(:each) do
9
+ @controller = MyController.new
10
+ end
11
+
12
+ describe "with view registering" do
13
+ it "should make the view available in a views hash and in an attribute" do
14
+ @controller.views[:my_view].should be_an_instance_of(MyView)
15
+ @controller.my_view.should be_an_instance_of(MyView)
16
+ @controller.views[:my_view].should == @controller.my_view
17
+ end
18
+ end
19
+
20
+ describe "with model registering" do
21
+ it "should make the model available in a models hash and in an attribute" do
22
+ @controller.models[:my_model].should be_an_instance_of(MyModel)
23
+ @controller.my_model.should be_an_instance_of(MyModel)
24
+ @controller.models[:my_model].should == @controller.my_model
25
+ end
26
+
27
+ it "should be notified using named observable property change calls" do
28
+ @controller.my_other_model_instance.my_property = 1
29
+ @controller.message.should == "Property my_property of named observable my_other_model_instance changed from to 1."
30
+ end
31
+ end
32
+
33
+ describe "with controller registering" do
34
+ it "should make the controller available in a controllers hash and in an attribute" do
35
+ @controller.controllers[:my_child_controller].should be_an_instance_of(MyChildController)
36
+ @controller.my_child_controller.should be_an_instance_of(MyChildController)
37
+ @controller.controllers[:my_child_controller].should == @controller.my_child_controller
38
+ end
39
+ end
40
+
41
+ describe "with initialization hooks" do
42
+ it "should call before initialize and after initialize methods" do
43
+ controller = MyController.new
44
+ controller.before_initialize_called?.should be_true
45
+ controller.after_initialize_called?.should be_true
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'models')
4
+
5
+ describe RuGUI::BaseModel do
6
+ describe "with initialization hooks" do
7
+ it "should call before initialize and after initialize methods" do
8
+ model = MyModel.new
9
+ model.before_initialize_called?.should be_true
10
+ model.after_initialize_called?.should be_true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'view_helpers')
4
+
5
+ describe RuGUI::BaseViewHelper do
6
+ describe "with initialization hooks" do
7
+ it "should call before initialize and after initialize methods" do
8
+ view_helper = MyViewHelper.new
9
+ view_helper.before_initialize_called?.should be_true
10
+ view_helper.after_initialize_called?.should be_true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,92 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'views')
4
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'view_helpers')
5
+
6
+ describe RuGUI::BaseView do
7
+ before(:each) do
8
+ @my_view = MyView.new
9
+ @my_child_view = MyChildView.new
10
+ @my_other_view = MyOtherView.new
11
+ @my_other_view_instance = MyOtherView.new
12
+ end
13
+
14
+ describe "with view widget registering" do
15
+ it "should make widgets available as attributes in the view class instance" do
16
+ @my_view.top_window.should be_an_instance_of(Gtk::Window)
17
+ @my_view.vertical_container.should be_an_instance_of(Gtk::VBox)
18
+ @my_view.button_above.should be_an_instance_of(Gtk::Button)
19
+ @my_view.button_below.should be_an_instance_of(Gtk::Button)
20
+ @my_view.label.should be_an_instance_of(Gtk::Label)
21
+ end
22
+ end
23
+
24
+ describe "with builder file accessor" do
25
+ it "should return different value for different view classes" do
26
+ @my_view.builder_file.should_not == @my_other_view.builder_file
27
+ end
28
+
29
+ it "should return the same value for same view classes" do
30
+ @my_other_view.builder_file.should == @my_other_view_instance.builder_file
31
+ end
32
+
33
+ it "should return the same value for subclasses which don't override it" do
34
+ @my_view.builder_file.should == @my_child_view.builder_file
35
+ end
36
+ end
37
+
38
+ describe "when creating a view without builder file" do
39
+ it "should not raise error" do
40
+ lambda {
41
+ @no_builder_view_instance = NoBuilderView.new
42
+ }.should_not raise_error(RuGUI::BuilderFileNotFoundError)
43
+ end
44
+ end
45
+
46
+ describe "when including a child view into a parent view" do
47
+ it "should include the root widget of the child view into the specified widget in the parent view" do
48
+ @my_view.include_view :vertical_container, @my_child_view
49
+ @my_view.vertical_container.children.include?(@my_child_view.root_widget).should be_true
50
+ end
51
+ end
52
+
53
+ describe "whent removing a child view from a parent view" do
54
+ before do
55
+ @my_view.include_view :vertical_container, @my_child_view
56
+ end
57
+
58
+ it "should remove the root widget of the child view from the specified widget in the parent view" do
59
+ @my_view.remove_view :vertical_container, @my_child_view
60
+ @my_view.vertical_container.children.include?(@my_child_view.root_widget).should_not be_true
61
+ end
62
+ end
63
+
64
+ describe "with view helpers" do
65
+ it "should include a default view helper automatically if it exists" do
66
+ @my_view.respond_to?(:helper).should be_true
67
+ @my_view.helper.should be_an_instance_of(MyViewHelper)
68
+ end
69
+
70
+ it "should not include a default view helper automatically if it does not exists" do
71
+ @my_other_view.respond_to?(:helper).should be_false
72
+ end
73
+
74
+ it "should notify the view when an observable property is changed in the view helper" do
75
+ @my_view.helper.message = "another message"
76
+ @my_view.message.should == "MyViewHelper property message changed from Some label in the middle to another message"
77
+ end
78
+
79
+ it "should be notified using named observable property change calls" do
80
+ @my_view.my_other_view_helper_instance.message = "foo"
81
+ @my_view.message.should == "Property message of my_other_view_helper_instance changed from Some label in the middle to foo"
82
+ end
83
+ end
84
+
85
+ describe "with initialization hooks" do
86
+ it "should call before initialize and after initialize methods" do
87
+ view = MyView.new
88
+ view.before_initialize_called?.should be_true
89
+ view.after_initialize_called?.should be_true
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ class MyObjectWithLogSupport
4
+ include RuGUI::LogSupport
5
+ end
6
+
7
+ describe RuGUI::LogSupport do
8
+ before(:each) do
9
+ @my_object_with_log_support = MyObjectWithLogSupport.new
10
+ end
11
+
12
+ it "should have a default logger if it is not initialized" do
13
+ @my_object_with_log_support.respond_to?(:logger).should be_true
14
+ @my_object_with_log_support.logger.should be_an_instance_of(Logger)
15
+ end
16
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'observables')
3
+
4
+ describe RuGUI::ObservablePropertyProxy do
5
+ before(:each) do
6
+ @observable = FakeObservable.new
7
+ @custom_type = CustomType.new
8
+ @custom_type.custom_property = "initial_value"
9
+
10
+ @observable_properties = {
11
+ :object => RuGUI::ObservablePropertyProxy.new(Object.new, @observable, :my_object_observable_property),
12
+ :string => RuGUI::ObservablePropertyProxy.new("some_value", @observable, :my_string_observable_property),
13
+ :fixnum => RuGUI::ObservablePropertyProxy.new(1, @observable, :my_fixnum_observable_property),
14
+ :float => RuGUI::ObservablePropertyProxy.new(1.1, @observable, :my_float_observable_property),
15
+ :array => RuGUI::ObservablePropertyProxy.new([], @observable, :my_array_observable_property),
16
+ :hash => RuGUI::ObservablePropertyProxy.new({}, @observable, :my_hash_observable_property),
17
+ :custom_type => RuGUI::ObservablePropertyProxy.new(@custom_type, @observable, :my_custom_type_observable_property),
18
+ }
19
+ end
20
+
21
+ [:object, :string, :fixnum, :float, :array, :hash, :custom_type].each do |type|
22
+ describe "with #{type.to_s.camelize} observable properties" do
23
+ it "should work as proxy for #{type.to_s.camelize} methods" do
24
+ @observable_properties[type].should be_an_instance_of(type.to_s.camelize.constantize)
25
+ type.to_s.camelize.constantize.instance_methods.each do |method_name|
26
+ @observable_properties[type].respond_to?(method_name).should be_true
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "with notification" do
33
+ it "should notifiy the observable when calling methods that changes the observable property" do
34
+ @observable_properties[:string].reverse! # reversing a string
35
+ @observable.property_changed_message.should == "my_string_observable_property changed from some_value to eulav_emos"
36
+
37
+ @observable_properties[:array] << 1 # adding an element into an array
38
+ @observable.property_changed_message.should == "my_array_observable_property changed from to 1"
39
+
40
+ @observable_properties[:hash][:key] = "value" # setting or changing a value in a hash
41
+ @observable.property_changed_message.should == "my_hash_observable_property changed from to keyvalue"
42
+
43
+ @observable_properties[:custom_type].change_custom_property("new_value") # calling a custom method which changes the property
44
+ @observable.property_changed_message.should == "my_custom_type_observable_property changed from initial_value to new_value"
45
+
46
+ @observable_properties[:custom_type].custom_property = "another_new_value" # changing a custom property with setter method
47
+ @observable.property_changed_message.should == "my_custom_type_observable_property changed from new_value to another_new_value"
48
+ end
49
+
50
+ it "should not notifiy the observable when calling methods that does not changes the observable property" do
51
+ @observable_properties[:string].reverse # reversing a string and returning a new copy of it
52
+ @observable.property_changed_message.should be_nil
53
+
54
+ @observable_properties[:array].index("some_value") # getting an element in the array
55
+ @observable.property_changed_message.should be_nil
56
+
57
+ @observable_properties[:hash].include?("some_key") # checking if a key is included in a hash
58
+ @observable.property_changed_message.should be_nil
59
+
60
+ @observable_properties[:custom_type].custom_method # calling a custom method which does not change
61
+ @observable.property_changed_message.should be_nil
62
+
63
+ @observable_properties[:custom_type].custom_method_with_parameters("something", "something else", "arg1", "arg2", "arg...") # calling a custom method which does not change
64
+ @observable.property_changed_message.should be_nil
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,283 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'helpers', 'observables')
4
+
5
+ describe RuGUI::ObservablePropertySupport do
6
+ before(:each) do
7
+ @observable = AnotherFakeObservable.new
8
+ @observer = AnotherFakeObserver.new
9
+ @observable.register_observer(@observer)
10
+ end
11
+
12
+ describe "with notification" do
13
+ it "should notify the observer when setting a new value in a observable property" do
14
+ @observable.my_observable_property = "something"
15
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from to something"
16
+
17
+ @observable.my_observable_property = 1
18
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from something to 1"
19
+
20
+ @observable.my_observable_property = ["somearray"]
21
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from 1 to somearray"
22
+
23
+ @observable.my_observable_property = {'key' => "value"}
24
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from somearray to key"
25
+ end
26
+
27
+ it "should notify the observer when changing the value of a observable property" do
28
+ @observable.my_observable_property = "something"
29
+ @observable.my_observable_property << "_else"
30
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from something to something_else"
31
+
32
+ @observable.my_observable_property = ["somearray"]
33
+ @observable.my_observable_property << "another_value"
34
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from somearray to somearrayanother_value"
35
+
36
+ @observable.my_observable_property = {'key' => "value"}
37
+ @observable.my_observable_property['another_key'] = "another_value"
38
+ @observer.property_updated_message.should == "AnotherFakeObservable property my_observable_property changed from key to another_keykey"
39
+ end
40
+
41
+ it "should not notify the observer when setting the same value in a observable property" do
42
+ set_same_value_twice_clearing_property_updated_message("something")
43
+ @observer.property_updated_message.should be_nil
44
+
45
+ set_same_value_twice_clearing_property_updated_message(["somearray"])
46
+ @observer.property_updated_message.should be_nil
47
+
48
+ set_same_value_twice_clearing_property_updated_message({'key' => "value"})
49
+ @observer.property_updated_message.should be_nil
50
+ end
51
+
52
+ def set_same_value_twice_clearing_property_updated_message(value)
53
+ @observable.my_observable_property = value
54
+ @observer.property_updated_message = nil
55
+ @observable.my_observable_property = value
56
+ end
57
+ end
58
+
59
+ describe "with CustomType observable properties" do
60
+ it "should notify the observer when changing the CustomType instance changes" do
61
+ custom_type_fake_observable = CustomTypeFakeObservable.new
62
+ custom_type_fake_observable.register_observer(@observer)
63
+
64
+ # Setting a value.
65
+ custom_type_fake_observable.custom_type_observable_property.core_observable_property = "foo"
66
+
67
+ # The observer must be notified, the message itself does not need to be meaniful
68
+ @observer.property_updated_message.should == "CustomTypeFakeObservable property custom_type_observable_property changed from AnotherFakeObservable to AnotherFakeObservable"
69
+
70
+ # Clearing the observer property_updated_message
71
+ @observer.property_updated_message = nil
72
+
73
+ # Reseting
74
+ custom_type_fake_observable.reset!
75
+
76
+ # The observer must be notified, the message itself does not need to be meaniful
77
+ @observer.property_updated_message.should == "CustomTypeFakeObservable property custom_type_observable_property changed from AnotherFakeObservable to AnotherFakeObservable"
78
+ end
79
+ end
80
+
81
+ describe "with observable property options" do
82
+ it "should initialize properties configured with an initial value properly" do
83
+ @observable.initialized_observable_property.should == "some_initial_value"
84
+ end
85
+
86
+ it "should set the configured reset_value when reseting an observable" do
87
+ @observable.resetable_observable_property.should be_nil
88
+ @observable.reset!
89
+ @observable.resetable_observable_property.should == "some_reset_value"
90
+ end
91
+
92
+ it "should set the inital_value and the reset_value as appropriate" do
93
+ @observable.initialized_and_resetable_observable_property.should == "some_initial_value"
94
+ @observable.reset!
95
+ @observable.initialized_and_resetable_observable_property.should == "some_reset_value"
96
+ end
97
+
98
+ it "should not be shared among different observable classes" do
99
+ observable_properties_options = {
100
+ :core_observable_property => { :core => true, :initial_value => "some_initial_value", :reset_value => "some_initial_value" },
101
+ :initialized_observable_property => { :core => false, :initial_value => "some_initial_value", :reset_value => "some_initial_value" },
102
+ :resetable_observable_property => { :core => false, :initial_value => nil, :reset_value => "some_reset_value" },
103
+ :initialized_and_resetable_observable_property => { :core => false, :initial_value => "some_initial_value", :reset_value => "some_reset_value" },
104
+ :my_observable_property => { :core => false, :initial_value => nil, :reset_value => nil },
105
+ :my_array_observable_property => { :reset_value => [], :initial_value => [], :core => false },
106
+ :my_hash_observable_property => { :reset_value => {}, :initial_value => {}, :core => false },
107
+ }
108
+ AnotherFakeObservable.observable_properties_options.should == observable_properties_options
109
+
110
+ observable_properties_options = {
111
+ :another_observable_property => {:core => false, :initial_value => "some_other_initial_value", :reset_value => "some_other_initial_value"},
112
+ :first_core_observable_property => {:core => true, :initial_value => "first", :reset_value => "first"},
113
+ :second_core_observable_property => {:core => true, :initial_value => "second", :reset_value => "second"},
114
+ }
115
+ SomeOtherFakeObservable.observable_properties_options.should == observable_properties_options
116
+ end
117
+
118
+ it "should not let initial_value and reset_value be modified when the property value changes" do
119
+ AnotherFakeObservable.observable_properties_options[:my_array_observable_property][:initial_value].should == []
120
+ AnotherFakeObservable.observable_properties_options[:my_array_observable_property][:reset_value].should == []
121
+
122
+ AnotherFakeObservable.observable_properties_options[:my_hash_observable_property][:initial_value].should == {}
123
+ AnotherFakeObservable.observable_properties_options[:my_hash_observable_property][:reset_value].should == {}
124
+
125
+ @observable.my_array_observable_property << 1
126
+ AnotherFakeObservable.observable_properties_options[:my_array_observable_property][:initial_value].should == []
127
+ AnotherFakeObservable.observable_properties_options[:my_array_observable_property][:reset_value].should == []
128
+
129
+ @observable.my_hash_observable_property[:foo] = 'bar'
130
+ AnotherFakeObservable.observable_properties_options[:my_hash_observable_property][:initial_value].should == {}
131
+ AnotherFakeObservable.observable_properties_options[:my_hash_observable_property][:reset_value].should == {}
132
+ end
133
+
134
+ it "should prevent properties from being reset if configured" do
135
+ observable = ResetPreventedFakeObservable.new
136
+ observable.reset_prevented_observable_property = 'bar'
137
+ observable.reset!
138
+ observable.reset_prevented_observable_property.should == 'bar'
139
+ end
140
+
141
+ it "should prevent properties from being reset even if a :reset_value was configured" do
142
+ observable = ResetPreventedFakeObservable.new
143
+ observable.reset_prevented_with_reset_value_observable_property = 'bar'
144
+ observable.reset!
145
+ observable.reset_prevented_with_reset_value_observable_property.should == 'bar'
146
+ end
147
+
148
+ it "should create 'question' methods for configured boolean properties" do
149
+ observable = BooleanPropertiesFakeObservable.new
150
+ observable.boolean_observable_property = true
151
+ observable.respond_to?(:boolean_observable_property?).should be_true
152
+ observable.boolean_observable_property?.should be_true
153
+ end
154
+
155
+ it "should not create 'question' methods for non boolean properties" do
156
+ observable = BooleanPropertiesFakeObservable.new
157
+ observable.non_boolean_observable_property = "any other value"
158
+ observable.respond_to?(:non_boolean_observable_property?).should be_false
159
+ end
160
+ end
161
+
162
+ describe "with two instances comparison" do
163
+ it "should be equals when all configured core observable properties are equals" do
164
+ some_other_observable = AnotherFakeObservable.new
165
+ some_other_observable.should == @observable
166
+ end
167
+
168
+ it "should not be equals when at least one of the configured core observable properties are not equals" do
169
+ some_other_observable1 = SomeOtherFakeObservable.new
170
+ some_other_observable1.first_core_observable_property = "different_value"
171
+ some_other_observable2 = SomeOtherFakeObservable.new
172
+ some_other_observable1.should_not == some_other_observable2
173
+
174
+ some_other_observable1 = SomeOtherFakeObservable.new
175
+ some_other_observable2 = SomeOtherFakeObservable.new
176
+ some_other_observable2.first_core_observable_property = "different_value"
177
+ some_other_observable1.should_not == some_other_observable2
178
+ end
179
+ end
180
+
181
+ describe "with observable properties copy" do
182
+ before(:each) do
183
+ @parent = ParentFakeObservable.new
184
+ @child = ChildFakeObservable.new
185
+ @parent.child_observable_property = @child
186
+
187
+ @parent.my_own_observable_property = "parent"
188
+ @child.my_observable_property = "child"
189
+
190
+ @another_parent = ParentFakeObservable.new
191
+ @another_child = ChildFakeObservable.new
192
+ @another_parent.child_observable_property = @another_child
193
+
194
+ @another_parent.my_own_observable_property = "another_parent"
195
+ @another_child.my_observable_property = "another child"
196
+ end
197
+
198
+ it "should copy all observable properties from observables which have common properties" do
199
+ @parent.copy_observable_properties_from(@another_parent)
200
+ @parent.my_own_observable_property.should == @another_parent.my_own_observable_property
201
+ end
202
+
203
+ it "should perform deep copy of observable properties which holds observables" do
204
+ @parent.copy_observable_properties_from(@another_parent)
205
+ @parent.child_observable_property.should == @another_parent.child_observable_property
206
+ end
207
+
208
+ it "should not perform deep copy if 'deep' parameter is false" do
209
+ @parent.copy_observable_properties_from(@another_parent, false)
210
+ @parent.my_own_observable_property.should == @another_parent.my_own_observable_property
211
+ @parent.child_observable_property.should_not == @another_parent.child_observable_property
212
+ end
213
+ end
214
+
215
+ describe "with observable properties mapped for an instance" do
216
+ before(:each) do
217
+ @observable = SomeOtherFakeObservable.new
218
+ @observable.first_core_observable_property = "first value"
219
+ @observable.second_core_observable_property = "second value"
220
+ @observable.another_observable_property = "another observable value"
221
+
222
+ @mock_observable_properties = {
223
+ :first_core_observable_property => "first value",
224
+ :second_core_observable_property => "second value",
225
+ :another_observable_property => "another observable value"
226
+ }
227
+
228
+ @another_mock_observable_properties = {
229
+ :another_observable_property => "another",
230
+ :first_core_observable_property => "first",
231
+ :second_core_observable_property => "second"
232
+ }
233
+ end
234
+
235
+ it "should return a map of all observable properties with theirs values" do
236
+ @observable.observable_properties.should == @mock_observable_properties
237
+ end
238
+
239
+ describe "with initial value in initialization method" do
240
+ it "should set observable properties values" do
241
+ observable = SomeOtherFakeObservable.new(@mock_observable_properties)
242
+ observable.observable_properties.should == @mock_observable_properties
243
+ end
244
+ end
245
+
246
+ describe "without initial value in initialization method" do
247
+ it "should use :initial_value for observable properties values" do
248
+ observable = SomeOtherFakeObservable.new :another_observable_property => "another"
249
+ observable.observable_properties.should == @another_mock_observable_properties
250
+ end
251
+ end
252
+
253
+ describe "updating observable properties values" do
254
+ before do
255
+ @observable = SomeOtherFakeObservable.new :another_observable_property => "fake data"
256
+ end
257
+
258
+ it "should update values" do
259
+ @observable.update_observable_properties({ :another_observable_property => "another" })
260
+ @observable.observable_properties.should == @another_mock_observable_properties
261
+ end
262
+
263
+ it "should ignore non observable properties values" do
264
+ @observable.update_observable_properties({ :another_observable_property => "another", :id => 151 })
265
+ @observable.observable_properties.should == @another_mock_observable_properties
266
+ end
267
+ end
268
+
269
+ describe "with indifferent hash access" do
270
+ it "should accept property names with both string or symbol keys" do
271
+ observable = SomeOtherFakeObservable.new :another_observable_property => "fake data"
272
+ observable.another_observable_property.should == "fake data"
273
+ observable.update_observable_properties({ :another_observable_property => "another" })
274
+ observable.another_observable_property.should == "another"
275
+
276
+ observable = SomeOtherFakeObservable.new 'another_observable_property' => "fake data"
277
+ observable.another_observable_property.should == "fake data"
278
+ observable.update_observable_properties({ 'another_observable_property' => "another" })
279
+ observable.another_observable_property.should == "another"
280
+ end
281
+ end
282
+ end
283
+ end