glimmer 0.1.0.0

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 (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