glimmer 0.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/COPYING.LGPL +504 -0
  2. data/README +27 -0
  3. data/samples/contactmanager/contact.rb +12 -0
  4. data/samples/contactmanager/contact_manager.rb +65 -0
  5. data/samples/contactmanager/contact_manager_presenter.rb +23 -0
  6. data/samples/contactmanager/contact_repository.rb +27 -0
  7. data/samples/hello_world.rb +26 -0
  8. data/samples/login.rb +97 -0
  9. data/samples/tictactoe/tic_tac_toe.rb +67 -0
  10. data/samples/tictactoe/tic_tac_toe_board.rb +149 -0
  11. data/src/command_handler.rb +11 -0
  12. data/src/command_handler_chain_factory.rb +23 -0
  13. data/src/command_handler_chain_link.rb +22 -0
  14. data/src/command_handlers.rb +26 -0
  15. data/src/command_handlers/bind_command_handler.rb +29 -0
  16. data/src/command_handlers/data_binding_command_handler.rb +64 -0
  17. data/src/command_handlers/models/model_observer.rb +25 -0
  18. data/src/command_handlers/models/observable_array.rb +46 -0
  19. data/src/command_handlers/models/observable_model.rb +35 -0
  20. data/src/command_handlers/models/r_runnable.rb +14 -0
  21. data/src/command_handlers/models/r_shell.rb +27 -0
  22. data/src/command_handlers/models/r_widget.rb +146 -0
  23. data/src/command_handlers/models/r_widget_listener.rb +12 -0
  24. data/src/command_handlers/models/r_widget_packages.rb +9 -0
  25. data/src/command_handlers/models/table_items_updater.rb +39 -0
  26. data/src/command_handlers/models/widget_observer.rb +23 -0
  27. data/src/command_handlers/shell_command_handler.rb +18 -0
  28. data/src/command_handlers/swt_constant_command_handler.rb +22 -0
  29. data/src/command_handlers/table_column_properties_data_binding_command_handler.rb +24 -0
  30. data/src/command_handlers/table_items_data_binding_command_handler.rb +30 -0
  31. data/src/command_handlers/widget_command_handler.rb +26 -0
  32. data/src/command_handlers/widget_listener_command_handler.rb +35 -0
  33. data/src/command_handlers/widget_method_command_handler.rb +22 -0
  34. data/src/glimmer.rb +45 -0
  35. data/src/parent.rb +8 -0
  36. data/src/shine.rb +24 -0
  37. data/src/swt.rb +10 -0
  38. data/src/xml.rb +10 -0
  39. data/src/xml_command_handlers.rb +18 -0
  40. data/src/xml_command_handlers/html_command_handler.rb +49 -0
  41. data/src/xml_command_handlers/models/depth_first_search_iterator.rb +20 -0
  42. data/src/xml_command_handlers/models/name_space_visitor.rb +21 -0
  43. data/src/xml_command_handlers/models/node.rb +83 -0
  44. data/src/xml_command_handlers/models/node_visitor.rb +12 -0
  45. data/src/xml_command_handlers/models/xml_visitor.rb +62 -0
  46. data/src/xml_command_handlers/xml_command_handler.rb +22 -0
  47. data/src/xml_command_handlers/xml_name_space_command_handler.rb +34 -0
  48. data/src/xml_command_handlers/xml_tag_command_handler.rb +26 -0
  49. data/src/xml_command_handlers/xml_text_command_handler.rb +22 -0
  50. data/test/glimmer_constant_test.rb +36 -0
  51. data/test/glimmer_data_binding_test.rb +236 -0
  52. data/test/glimmer_listeners_test.rb +61 -0
  53. data/test/glimmer_shine_data_binding_test.rb +88 -0
  54. data/test/glimmer_table_data_binding_test.rb +135 -0
  55. data/test/glimmer_test.rb +233 -0
  56. data/test/observable_model_test.rb +27 -0
  57. data/test/r_widget_test.rb +52 -0
  58. data/test/samples/contactmanager/contact_manager_presenter_test.rb +60 -0
  59. data/test/samples/tictactoe/tic_tac_toe_test.rb +265 -0
  60. data/test/xml/glimmer_xml_test.rb +163 -0
  61. metadata +126 -0
data/README ADDED
@@ -0,0 +1,27 @@
1
+ Glimmer - a JRuby DSL that enables easy and efficient authoring of user-interfaces
2
+ using the robust platform-independent Eclipse SWT library. Glimmer comes with built-in
3
+ data-binding support to greatly facilitate synchronizing UI with domain models.
4
+
5
+ Copyright (C) 2007 Annas Al Maleh
6
+ Licensed under the LGPL. See /COPYING.LGPL for more details.
7
+
8
+ Instructions for use with stand-alone SWT:
9
+ 1. Download the "SWT binary and source" archive from the Eclipse site and follow their instructions.
10
+ http://download.eclipse.org/eclipse/downloads/drops/R-3.3.1.1-200710231652/details.php#SWT
11
+ 2. Have your program require the swt.rb file
12
+ 3. Create a class that includes the Glimmer module and you will be able to write Glimmer syntax
13
+
14
+ Instructions for use with Eclipse:
15
+ 1. Download and setup Eclipse 3.3 or 3.2
16
+ 2. Download and setup jRuby 1.0.2
17
+ 3. Modify Java launch command in jRuby script/batch file to include SWT libraries in both:
18
+ a. Classpath; must include %ECLIPSE_HOME%/plugins/org.eclipse.swt*.jar
19
+ For example with Eclipse 3.2 on Windows, we add the following:
20
+ -cp "%CLASSPATH%;%ECLIPSE_HOME%\plugins\org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar;%ECLIPSE_HOME%\plugins\org.eclipse.swt_3.2.0.v3232o.jar"
21
+ b. java.library.path; must point to %ECLIPSE_HOME%/plugins/org.eclipse.swt* folder
22
+ For example, with Eclipse 3.2 on Windows, we add the following:
23
+ -Djava.library.path="%ECLIPSE_HOME%\plugins\org.eclipse.swt.win32.win32.x86_3.2.0.v3232m"
24
+ 4. Have your program require the glimmer.rb file
25
+ 5. Create a class that includes the Glimmer module and you will be able to write Glimmer syntax
26
+
27
+ Check samples folder for examples on how to write Glimmer programs.
@@ -0,0 +1,12 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class Contact
5
+ attr_accessor :first_name, :last_name, :email
6
+
7
+ def initialize(attribute_map)
8
+ @first_name = attribute_map[:first_name]
9
+ @last_name = attribute_map[:last_name]
10
+ @email = attribute_map[:email]
11
+ end
12
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/contact_manager_presenter"
5
+ require File.dirname(__FILE__) + "/../../src/swt"
6
+
7
+ class RWidget
8
+ include_package 'org.eclipse.jface.viewers'
9
+ end
10
+
11
+ class ContactManager
12
+ extend Glimmer
13
+
14
+ include_package 'org.eclipse.swt'
15
+ include_package 'org.eclipse.swt.widgets'
16
+ include_package 'org.eclipse.swt.layout'
17
+ include_package 'org.eclipse.jface.viewers'
18
+
19
+ contact_manager_presenter = ContactManagerPresenter.new
20
+
21
+ shell {
22
+ text "Contact Manager"
23
+ composite {
24
+ composite {
25
+ layout GridLayout.new(2, false)
26
+ label {text "First &Name: "}
27
+ text {
28
+ text bind(contact_manager_presenter, :first_name)
29
+ }
30
+ label {text "&Last Name: "}
31
+ text {
32
+ text bind(contact_manager_presenter, :last_name)
33
+ }
34
+ label {text "&Email: "}
35
+ text {
36
+ text bind(contact_manager_presenter, :email)
37
+ }
38
+ }
39
+
40
+ table {
41
+ layout_data GridData.new(fill, fill, true, true)
42
+ table_column {
43
+ text "First Name"
44
+ width 80
45
+ }
46
+ table_column {
47
+ text "Last Name"
48
+ width 80
49
+ }
50
+ table_column {
51
+ text "Email"
52
+ width 120
53
+ }
54
+ items bind(contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
55
+ }
56
+
57
+ button {
58
+ text "&Find"
59
+ on_widget_selected {
60
+ contact_manager_presenter.find
61
+ }
62
+ }
63
+ }
64
+ }.open
65
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/contact_repository"
5
+
6
+ class ContactManagerPresenter
7
+ attr_accessor :results
8
+ @@contact_attributes = [:first_name, :last_name, :email]
9
+ @@contact_attributes.each {|attribute_name| attr_accessor attribute_name}
10
+
11
+ def initialize
12
+ @contact_repository = ContactRepository.new
13
+ @results = []
14
+ end
15
+
16
+ def find
17
+ filter_map = Hash.new
18
+ @@contact_attributes.each do |attribute_name|
19
+ filter_map[attribute_name] = self.send(attribute_name) if self.send(attribute_name)
20
+ end
21
+ self.results=@contact_repository.find(filter_map)
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/contact"
5
+
6
+ class ContactRepository
7
+ def initialize
8
+ @contacts = [
9
+ Contact.new(:first_name => "Anne", :last_name => "Sweeney", :email => "anne@sweeny.com"),
10
+ Contact.new(:first_name => "Beatrice", :last_name => "Jung", :email => "beatrice@jung.com"),
11
+ Contact.new(:first_name => "Frank", :last_name => "Deelio", :email => "frank@deelio.com"),
12
+ Contact.new(:first_name => "franky", :last_name => "miller", :email => "frank@miller.com"),
13
+ ]
14
+ end
15
+
16
+ def find(attribute_filter_map)
17
+ @contacts.find_all do |contact|
18
+ match = true
19
+ attribute_filter_map.keys.each do |attribute_name|
20
+ contact_value = contact.send(attribute_name).downcase
21
+ filter_value = attribute_filter_map[attribute_name].downcase
22
+ match = false unless contact_value.match(filter_value)
23
+ end
24
+ match
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "java"
5
+ require File.dirname(__FILE__) + "/../src/swt"
6
+
7
+ class HelloWorld
8
+ include_package 'org.eclipse.swt'
9
+ include_package 'org.eclipse.swt.layout'
10
+
11
+ include Glimmer
12
+
13
+ def launch
14
+ @shell = shell {
15
+ text "SWT"
16
+ composite {
17
+ label {
18
+ text "Hello World!"
19
+ }
20
+ }
21
+ }
22
+ @shell.open
23
+ end
24
+ end
25
+
26
+ HelloWorld.new.launch
data/samples/login.rb ADDED
@@ -0,0 +1,97 @@
1
+ # Copyright (C) 2007-2008 Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require "java"
5
+ require "observer"
6
+ require File.dirname(__FILE__) + "/../src/swt"
7
+
8
+ #Presents login screen data
9
+ class LoginPresenter
10
+
11
+ attr_accessor :user_name
12
+ attr_accessor :password
13
+ attr_accessor :status
14
+
15
+ def initialize
16
+ @user_name = ""
17
+ @password = ""
18
+ @status = "Logged Out"
19
+ end
20
+
21
+ def status=(status)
22
+ @status = status
23
+
24
+ #TODO add feature to bind dependent properties to master property
25
+ notify_observers("logged_in")
26
+ notify_observers("logged_out")
27
+ end
28
+
29
+ def logged_in
30
+ self.status == "Logged In"
31
+ end
32
+
33
+ def logged_out
34
+ !self.logged_in
35
+ end
36
+
37
+ def login
38
+ self.user_name = ""
39
+ self.password = ""
40
+ self.status = "Logged In"
41
+ end
42
+
43
+ def logout
44
+ self.user_name = ""
45
+ self.password = ""
46
+ self.status = "Logged Out"
47
+ end
48
+
49
+ end
50
+
51
+ #Login screen
52
+ class Login
53
+ include_package 'org.eclipse.swt'
54
+ include_package 'org.eclipse.swt.layout'
55
+
56
+ include Glimmer
57
+
58
+ def launch
59
+ presenter = LoginPresenter.new
60
+ @shell = shell {
61
+ text "Login"
62
+ composite {
63
+ layout GridLayout.new(2, false) #two columns with differing widths
64
+
65
+ label { text "Username:" } # goes in column 1
66
+ text { # goes in column 2
67
+ text bind(presenter, :user_name)
68
+ enabled bind(presenter, :logged_out)
69
+ }
70
+
71
+ label { text "Password:" }
72
+ text(SWT::PASSWORD | SWT::BORDER) {
73
+ text bind(presenter, :password)
74
+ enabled bind(presenter, :logged_out)
75
+ }
76
+
77
+ label { text "Status:" }
78
+ label { text bind(presenter, :status) }
79
+
80
+ button {
81
+ text "Login"
82
+ enabled bind(presenter, :logged_out)
83
+ on_widget_selected { presenter.login }
84
+ }
85
+
86
+ button {
87
+ text "Logout"
88
+ enabled bind(presenter, :logged_in)
89
+ on_widget_selected { presenter.logout }
90
+ }
91
+ }
92
+ }
93
+ @shell.open
94
+ end
95
+ end
96
+
97
+ Login.new.launch
@@ -0,0 +1,67 @@
1
+ # Copyright (C) 2007-2008 Nick Malnick and Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ require File.dirname(__FILE__) + "/../../src/swt"
5
+ require File.dirname(__FILE__) + "/tic_tac_toe_board"
6
+
7
+
8
+ class TicTacToe
9
+
10
+ include_package 'org.eclipse.swt'
11
+ include_package 'org.eclipse.swt.widgets'
12
+ include_package 'org.eclipse.swt.layout'
13
+
14
+ include Glimmer
15
+
16
+ def initialize
17
+ @tic_tac_toe_board = TicTacToeBoard.new
18
+ @main =
19
+ @shell = shell {
20
+ text "Tic-Tac-Toe"
21
+ composite {
22
+ layout GridLayout.new(3,true)
23
+ (1..3).each { |row_number|
24
+ (1..3).each { |column_number|
25
+ button { |button_parent|
26
+ layout_data GridData.new(fill, fill, true, true)
27
+ text bind(@tic_tac_toe_board.box(row_number, column_number), :sign)
28
+ enabled bind(@tic_tac_toe_board.box(row_number, column_number), :empty)
29
+ on_widget_selected {
30
+ @tic_tac_toe_board.mark_box(row_number, column_number)
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ @tic_tac_toe_board.extend(ObservableModel) #make board an observable model
38
+ @tic_tac_toe_board.add_observer("game_status", self)
39
+ end
40
+
41
+ def update(game_status)
42
+ display_win_message if game_status == TicTacToeBoard::WIN
43
+ display_draw_message if game_status == TicTacToeBoard::DRAW
44
+ end
45
+
46
+ def display_win_message()
47
+ display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
48
+ end
49
+
50
+ def display_draw_message()
51
+ display_game_over_message("Draw!")
52
+ end
53
+
54
+ def display_game_over_message(message)
55
+ message_box = MessageBox.new(@shell.widget)
56
+ message_box.setText("Game Over")
57
+ message_box.setMessage(message)
58
+ message_box.open
59
+ @tic_tac_toe_board.reset
60
+ end
61
+
62
+ def open
63
+ @main.open
64
+ end
65
+ end
66
+
67
+ TicTacToe.new.open
@@ -0,0 +1,149 @@
1
+ # Copyright (C) 2007-2008 Nick Malnick and Annas Al Maleh
2
+ # Licensed under the LGPL. See /COPYING.LGPL for more details.
3
+
4
+ class TicTacToeBox
5
+ EMPTY = ""
6
+ attr_accessor :sign, :empty
7
+
8
+ def initialize
9
+ reset
10
+ end
11
+
12
+ def mark_box(sign)
13
+ self.sign = sign
14
+ end
15
+
16
+ def reset
17
+ self.sign = EMPTY
18
+ end
19
+
20
+ def sign=(sign_symbol)
21
+ @sign = sign_symbol
22
+ self.empty = sign == EMPTY
23
+ end
24
+
25
+ def marked
26
+ ! empty
27
+ end
28
+ end
29
+
30
+ class TicTacToeBoard
31
+ DRAW = :draw
32
+ IN_PROGRESS = :in_progress
33
+ WIN = :win
34
+ attr :winning_sign
35
+ attr_accessor :game_status
36
+
37
+ def initialize
38
+ @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
39
+ build_grid
40
+ @winning_sign = TicTacToeBox::EMPTY
41
+ @game_status = IN_PROGRESS
42
+ end
43
+
44
+ #row and column numbers are 1-based
45
+ def mark_box(row_number, column_number)
46
+ box(row_number, column_number).mark_box(current_sign)
47
+ game_over? #updates winning sign
48
+ end
49
+
50
+ def current_sign
51
+ @current_sign = @sign_state_machine[@current_sign]
52
+ end
53
+
54
+ def box(row_number, column_number)
55
+ @grid[row_number-1][column_number-1]
56
+ end
57
+
58
+ def game_over?
59
+ win? or draw?
60
+ end
61
+
62
+ def win?
63
+ win = (row_win? or column_win? or diagonal_win?)
64
+ self.game_status=WIN if win
65
+ win
66
+ end
67
+
68
+ def reset
69
+ (1..3).each do |row_number|
70
+ (1..3).each do |column_number|
71
+ box(row_number, column_number).reset
72
+ end
73
+ end
74
+ @winning_sign = TicTacToeBox::EMPTY
75
+ @current_sign = nil
76
+ self.game_status=IN_PROGRESS
77
+ end
78
+
79
+ private
80
+
81
+ def build_grid
82
+ @grid = []
83
+ 3.times do |row_index| #0-based
84
+ @grid << []
85
+ 3.times { @grid[row_index] << TicTacToeBox.new }
86
+ end
87
+ end
88
+
89
+ def row_win?
90
+ (1..3).each do |row_number|
91
+ if row_has_same_sign(row_number)
92
+ @winning_sign = box(row_number, 1).sign
93
+ return true
94
+ end
95
+ end
96
+ false
97
+ end
98
+
99
+ def column_win?
100
+ (1..3).each do |column_number|
101
+ if column_has_same_sign(column_number)
102
+ @winning_sign = box(1, column_number).sign
103
+ return true
104
+ end
105
+ end
106
+ false
107
+ end
108
+
109
+ #needs refactoring if we ever decide to make the board size dynamic
110
+ def diagonal_win?
111
+ if (box(1,1).sign == box(2,2).sign) and (box(2,2).sign == box(3,3).sign) and box(1,1).marked
112
+ @winning_sign = box(1,1).sign
113
+ return true
114
+ end
115
+ if (box(3,1).sign == box(2,2).sign) and (box(2,2).sign == box(1,3).sign) and box(3,1).marked
116
+ @winning_sign = box(3,1).sign
117
+ return true
118
+ end
119
+ false
120
+ end
121
+
122
+ def draw?
123
+ @board_full = true
124
+ 3.times do |x|
125
+ 3.times do |y|
126
+ @board_full = false if box(x, y).empty
127
+ end
128
+ end
129
+ self.game_status = DRAW if @board_full
130
+ @board_full
131
+ end
132
+
133
+ def row_has_same_sign(number)
134
+ row_sign = box(number, 1).sign
135
+ [2, 3].each do |column|
136
+ return false unless row_sign == (box(number, column).sign)
137
+ end
138
+ true if box(number, 1).marked
139
+ end
140
+
141
+ def column_has_same_sign(number)
142
+ column_sign = box(1, number).sign
143
+ [2, 3].each do |row|
144
+ return false unless column_sign == (box(row, number).sign)
145
+ end
146
+ true if box(1, number).marked
147
+ end
148
+
149
+ end