win_gui 0.1.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 (164) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +43 -0
  5. data/Rakefile +58 -0
  6. data/VERSION +1 -0
  7. data/book_code/early_success/bundle.rb +34 -0
  8. data/book_code/early_success/english.txt +1 -0
  9. data/book_code/early_success/jruby_basics.rb +47 -0
  10. data/book_code/early_success/windows_basics.rb +97 -0
  11. data/book_code/guessing/locknote.rb +379 -0
  12. data/book_code/guessing/monkeyshines.rb +14 -0
  13. data/book_code/guessing/note.rb +120 -0
  14. data/book_code/guessing/note_spec.rb +175 -0
  15. data/book_code/guessing/replay.rb +21 -0
  16. data/book_code/guessing/seed.rb +9 -0
  17. data/book_code/guessing/spec_helper.rb +69 -0
  18. data/book_code/guessing/windows_gui.rb +247 -0
  19. data/book_code/home_stretch/junquenote.rb +151 -0
  20. data/book_code/home_stretch/locknote.rb +180 -0
  21. data/book_code/home_stretch/note.rb +144 -0
  22. data/book_code/home_stretch/note_spec.rb +191 -0
  23. data/book_code/home_stretch/spec_helper.rb +55 -0
  24. data/book_code/home_stretch/swing_gui.rb +50 -0
  25. data/book_code/home_stretch/windows_gui.rb +232 -0
  26. data/book_code/junquenote/exports.sh +10 -0
  27. data/book_code/junquenote/jruby_mac.sh +10 -0
  28. data/book_code/junquenote/junquenote_app.rb +262 -0
  29. data/book_code/novite/Rakefile +10 -0
  30. data/book_code/novite/app/controllers/application.rb +18 -0
  31. data/book_code/novite/app/controllers/guests_controller.rb +28 -0
  32. data/book_code/novite/app/controllers/parties_controller.rb +77 -0
  33. data/book_code/novite/app/helpers/application_helper.rb +11 -0
  34. data/book_code/novite/app/helpers/guests_helper.rb +10 -0
  35. data/book_code/novite/app/helpers/parties_helper.rb +10 -0
  36. data/book_code/novite/app/models/guest.rb +11 -0
  37. data/book_code/novite/app/models/party.rb +32 -0
  38. data/book_code/novite/app/models/party_mailer.rb +19 -0
  39. data/book_code/novite/app/views/layouts/application.rhtml +44 -0
  40. data/book_code/novite/app/views/parties/new.html.erb +42 -0
  41. data/book_code/novite/app/views/parties/show.html.erb +43 -0
  42. data/book_code/novite/app/views/party_mailer/invite.erb +17 -0
  43. data/book_code/novite/config/boot.rb +117 -0
  44. data/book_code/novite/config/database.yml +19 -0
  45. data/book_code/novite/config/environment.rb +67 -0
  46. data/book_code/novite/config/environments/development.rb +29 -0
  47. data/book_code/novite/config/environments/production.rb +27 -0
  48. data/book_code/novite/config/environments/test.rb +30 -0
  49. data/book_code/novite/config/initializers/inflections.rb +18 -0
  50. data/book_code/novite/config/initializers/mime_types.rb +13 -0
  51. data/book_code/novite/config/routes.rb +47 -0
  52. data/book_code/novite/db/migrate/001_create_parties.rb +26 -0
  53. data/book_code/novite/db/migrate/002_create_guests.rb +23 -0
  54. data/book_code/novite/db/schema.rb +41 -0
  55. data/book_code/novite/log/empty.txt +0 -0
  56. data/book_code/novite/public/.htaccess +40 -0
  57. data/book_code/novite/public/404.html +38 -0
  58. data/book_code/novite/public/422.html +38 -0
  59. data/book_code/novite/public/500.html +38 -0
  60. data/book_code/novite/public/dispatch.cgi +10 -0
  61. data/book_code/novite/public/dispatch.fcgi +24 -0
  62. data/book_code/novite/public/dispatch.rb +18 -0
  63. data/book_code/novite/public/favicon.ico +0 -0
  64. data/book_code/novite/public/images/rails.png +0 -0
  65. data/book_code/novite/public/index.html +285 -0
  66. data/book_code/novite/public/javascripts/application.js +10 -0
  67. data/book_code/novite/public/javascripts/controls.js +971 -0
  68. data/book_code/novite/public/javascripts/dragdrop.js +980 -0
  69. data/book_code/novite/public/javascripts/effects.js +1128 -0
  70. data/book_code/novite/public/javascripts/prototype.js +4233 -0
  71. data/book_code/novite/public/robots.txt +5 -0
  72. data/book_code/novite/script/about +3 -0
  73. data/book_code/novite/script/console +3 -0
  74. data/book_code/novite/script/destroy +3 -0
  75. data/book_code/novite/script/generate +3 -0
  76. data/book_code/novite/script/performance/benchmarker +3 -0
  77. data/book_code/novite/script/performance/profiler +3 -0
  78. data/book_code/novite/script/performance/request +3 -0
  79. data/book_code/novite/script/plugin +3 -0
  80. data/book_code/novite/script/process/inspector +3 -0
  81. data/book_code/novite/script/process/reaper +3 -0
  82. data/book_code/novite/script/process/spawner +3 -0
  83. data/book_code/novite/script/runner +3 -0
  84. data/book_code/novite/script/server +3 -0
  85. data/book_code/novite/test/test_helper.rb +46 -0
  86. data/book_code/one_more_thing/applescript.rb +68 -0
  87. data/book_code/one_more_thing/note_spec.rb +50 -0
  88. data/book_code/one_more_thing/spec_helper.rb +17 -0
  89. data/book_code/one_more_thing/textedit-pure.rb +28 -0
  90. data/book_code/one_more_thing/textedit.applescript +26 -0
  91. data/book_code/one_more_thing/textedit.rb +32 -0
  92. data/book_code/one_more_thing/textnote.rb +87 -0
  93. data/book_code/simplify/junquenote.rb +48 -0
  94. data/book_code/simplify/locknote.rb +46 -0
  95. data/book_code/simplify/note.rb +35 -0
  96. data/book_code/simplify/note_spec.rb +28 -0
  97. data/book_code/simplify/swing_gui.rb +45 -0
  98. data/book_code/simplify/windows_gui.rb +232 -0
  99. data/book_code/simplify/windows_gui_spec.rb +35 -0
  100. data/book_code/story/invite.story +19 -0
  101. data/book_code/story/journal.txt +29 -0
  102. data/book_code/story/novite_stories.rb +156 -0
  103. data/book_code/story/party.rb +149 -0
  104. data/book_code/story/password.rb +61 -0
  105. data/book_code/story/password.story +26 -0
  106. data/book_code/story/rsvp.story +29 -0
  107. data/book_code/tables/TestTime.html +93 -0
  108. data/book_code/tables/TestTimeSample.html +63 -0
  109. data/book_code/tables/calculate_time.rb +39 -0
  110. data/book_code/tables/calculator.rb +108 -0
  111. data/book_code/tables/calculator_actions.rb +27 -0
  112. data/book_code/tables/calculator_spec.rb +47 -0
  113. data/book_code/tables/fit.rb +32 -0
  114. data/book_code/tables/matrix.rb +109 -0
  115. data/book_code/tables/pseudocode.rb +17 -0
  116. data/book_code/tubes/book_selenium.rb +67 -0
  117. data/book_code/tubes/book_watir.rb +60 -0
  118. data/book_code/tubes/dragdrop.html +81 -0
  119. data/book_code/tubes/html_capture.rb +33 -0
  120. data/book_code/tubes/joke_list.rb +67 -0
  121. data/book_code/tubes/list_spec.rb +41 -0
  122. data/book_code/tubes/search_spec.rb +32 -0
  123. data/book_code/tubes/selenium_example.rb +66 -0
  124. data/book_code/tubes/selenium_link.rb +23 -0
  125. data/book_code/tubes/web_server.rb +14 -0
  126. data/book_code/windows/wgui.rb +29 -0
  127. data/book_code/windows/wobj.rb +25 -0
  128. data/book_code/windows/wsh.rb +25 -0
  129. data/book_code/with_rspec/empty_spec.rb +13 -0
  130. data/book_code/with_rspec/junquenote.rb +60 -0
  131. data/book_code/with_rspec/locknote.rb +129 -0
  132. data/book_code/with_rspec/note_spec.rb +32 -0
  133. data/book_code/with_rspec/should_examples.rb +18 -0
  134. data/exp/exp.rb +6 -0
  135. data/exp/exp_encodings.rb +40 -0
  136. data/exp/exp_enum_windows.rb +60 -0
  137. data/exp/exp_quik.rb +38 -0
  138. data/exp/exp_wsh.rb +115 -0
  139. data/exp/old/windows_basics.rb +80 -0
  140. data/exp/old/wnote.rb +80 -0
  141. data/exp/old/wnote_spec.rb +20 -0
  142. data/features/step_definitions/win_gui_steps.rb +0 -0
  143. data/features/support/env.rb +4 -0
  144. data/features/win_gui.feature +9 -0
  145. data/lib/note/java/jemmy.jar +0 -0
  146. data/lib/note/java/jnote.rb +48 -0
  147. data/lib/note/java/jruby_basics.rb +37 -0
  148. data/lib/note/java/junquenote_app.rb +262 -0
  149. data/lib/note/java/note_spec.rb +20 -0
  150. data/lib/note/win/locknote.rb +19 -0
  151. data/lib/note.rb +15 -0
  152. data/lib/win_gui/constants.rb +66 -0
  153. data/lib/win_gui/string_extensions.rb +24 -0
  154. data/lib/win_gui/win_gui.rb +274 -0
  155. data/lib/win_gui/window.rb +70 -0
  156. data/lib/win_gui.rb +3 -0
  157. data/spec/note/win/locknote_spec.rb +7 -0
  158. data/spec/spec.opts +2 -0
  159. data/spec/spec_helper.rb +100 -0
  160. data/spec/test_apps/locknote/LockNote.exe +0 -0
  161. data/spec/win_gui/string_extensions_spec.rb +61 -0
  162. data/spec/win_gui/win_gui_spec.rb +733 -0
  163. data/spec/win_gui/window_spec.rb +124 -0
  164. metadata +251 -0
@@ -0,0 +1,262 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'java'
10
+ require 'rubygems'
11
+ require 'cheri/swing'
12
+ require 'crypt/gost'
13
+
14
+ include_class javax.swing.JOptionPane
15
+
16
+ class String
17
+ def encrypt(pw)
18
+ padded = pw + "\0" * [0, 8 - pw.length].max
19
+ Crypt::Gost.new(padded).encrypt_string(self)
20
+ rescue
21
+ return '(wrong password)'
22
+ end
23
+
24
+ def decrypt(pw)
25
+ padded = pw + "\0" * [0, 8 - pw.length].max
26
+ Crypt::Gost.new(padded).decrypt_string(self)
27
+ rescue
28
+ return '(wrong password)'
29
+ end
30
+ end
31
+
32
+ class JunqueNoteApp
33
+ include Cheri::Swing
34
+
35
+ def initialize
36
+ swing[:auto]
37
+
38
+ @frame = swing.frame('JunqueNote') do |f|
39
+ size 400, 300
40
+ box_layout f, :Y_AXIS
41
+
42
+ menu_bar do
43
+ menu('File') do
44
+ menu_item('Open...') {on_click {open} }
45
+ menu_item('Change Password...') {on_click {change_password} }
46
+ menu_item('Save As...') {on_click {save_as} }
47
+ menu_item('Exit') {on_click {exit_app} }
48
+ end
49
+
50
+ menu('Edit') do
51
+ menu_item('Undo') {on_click {@text_area.text = @state.pop} }
52
+ menu_item('Cut') {on_click {@state.push(@text_area.text); @text_area.cut} }
53
+ menu_item('Copy') {on_click {@state.push(@text_area.text); @text_area.copy} }
54
+ menu_item('Paste') {on_click {@state.push(@text_area.text); @text_area.paste} }
55
+
56
+ menu_item('Find...') {on_click {find} }
57
+ menu_item('Find Exact Case...') {on_click {find :case} }
58
+ menu_item('Reverse Find...') {on_click {find :reverse} }
59
+ menu_item('Reverse Find Exact Case...') {on_click {find :case_reverse} }
60
+ menu_item('Find Next') {on_click {find @how, @term} }
61
+ end
62
+
63
+ menu('Help') do
64
+ menu_item('About JunqueNote...') {on_click {about} }
65
+ end
66
+ end
67
+
68
+ @text_area = text_area('Welcome to JunqueNote!') do
69
+ on_key_pressed {|event| @state.push(@text_area.text); @dirty = true}
70
+ end
71
+ end
72
+
73
+ @state = [@text_area.text]
74
+ @frame.visible = true
75
+ end
76
+
77
+ def request_filename(button = 'Save')
78
+ pane = JOptionPane.new \
79
+ 'Please enter a filename',
80
+ JOptionPane::PLAIN_MESSAGE,
81
+ JOptionPane::OK_CANCEL_OPTION,
82
+ nil,
83
+ [button,'Cancel'].to_java,
84
+ button
85
+ pane.wants_input = true
86
+ pane.create_dialog(@frame, 'Input').show
87
+
88
+ button == pane.value ? pane.input_value : nil
89
+ end
90
+
91
+ def save_as(filename = nil)
92
+ save_name = filename || request_filename
93
+ return if save_name.nil?
94
+
95
+ @filename = save_name
96
+
97
+ if @password.nil?
98
+ @password = JOptionPane.show_input_dialog "Please assign a password"
99
+ return if @password.nil?
100
+ confirmation = JOptionPane.show_input_dialog "Please confirm the password"
101
+ return if confirmation.nil?
102
+
103
+ if @password != confirmation
104
+ JOptionPane.show_message_dialog(
105
+ @frame,
106
+ "The password and confirmation don't match",
107
+ "Oops",
108
+ JOptionPane::YES_NO_OPTION)
109
+
110
+ return
111
+ end
112
+ end
113
+
114
+ File.delete @filename if File.exists? @filename
115
+ File.open @filename, 'wb' do |f|
116
+ plaintext = "JunqueNote\n#{@text_area.text.length}\n#{@text_area.text}"
117
+ encrypted = plaintext.encrypt(@password)
118
+ f.write encrypted
119
+ end
120
+
121
+ @dirty = false
122
+ end
123
+
124
+ def open
125
+ @filename = request_filename 'Open'
126
+ if @filename.nil?
127
+ @frame.dispose
128
+ return
129
+ end
130
+
131
+ @password = JOptionPane.show_input_dialog "Please enter the password"
132
+ if @password.nil?
133
+ @frame.dispose
134
+ return
135
+ end
136
+
137
+ encrypted = File.open(@filename, 'rb') {|f| f.read}
138
+ init, length, contents = encrypted.decrypt(@password).split($;, 3)
139
+
140
+ if init == 'JunqueNote'
141
+ contents = contents[0, length.to_i]
142
+ @text_area.text = contents
143
+ @state = [contents]
144
+ @dirty = false
145
+ else
146
+ JOptionPane.show_message_dialog(
147
+ @frame,
148
+ "The password doesn't match",
149
+ "Oops",
150
+ JOptionPane::YES_NO_OPTION)
151
+
152
+ @frame.dispose
153
+ end
154
+ end
155
+
156
+ def change_password
157
+ old_password = JOptionPane.show_input_dialog "Please enter the password"
158
+ return if old_password.nil?
159
+
160
+ if old_password != @password
161
+ JOptionPane.show_message_dialog(
162
+ @frame,
163
+ "The password doesn't match",
164
+ "Oops",
165
+ JOptionPane::YES_NO_OPTION)
166
+
167
+ return
168
+ end
169
+
170
+ new_password = JOptionPane.show_input_dialog "Please enter a password"
171
+ return if new_password.nil?
172
+ confirmation = JOptionPane.show_input_dialog "Please confirm the password"
173
+ return if confirmation.nil?
174
+
175
+ if new_password != confirmation
176
+ JOptionPane.show_message_dialog(
177
+ @frame,
178
+ "The password and confirmation don't match",
179
+ "Oops",
180
+ JOptionPane::YES_NO_OPTION)
181
+
182
+ return
183
+ end
184
+
185
+ @password = new_password
186
+
187
+ File.delete @filename if File.exists? @filename
188
+ File.open @filename, 'wb' do |f|
189
+ plaintext = "JunqueNote\n#{@text_area.text.length}\n#{@text_area.text}"
190
+ encrypted = plaintext.encrypt(@password)
191
+ f.write encrypted
192
+ end
193
+
194
+ @dirty = false
195
+ end
196
+
197
+ def exit_app
198
+ should_save = if @dirty
199
+ 0 == JOptionPane.show_confirm_dialog(
200
+ nil,
201
+ "Wanna save first?",
202
+ "Quittin' time",
203
+ JOptionPane::YES_NO_OPTION)
204
+ else
205
+ false
206
+ end
207
+
208
+ save_as(@filename) if should_save
209
+ @frame.dispose
210
+ end
211
+
212
+ def about
213
+ JOptionPane.show_message_dialog(
214
+ @frame,
215
+ "A hypothetical JRuby port of LockNote",
216
+ "About JunqueNote",
217
+ JOptionPane::INFORMATION_MESSAGE)
218
+ end
219
+
220
+ def find(how = nil, term = nil)
221
+ term ||= JOptionPane.show_input_dialog "Please enter the search term"
222
+ return unless term
223
+
224
+ @how = how
225
+ @term = term
226
+
227
+ pattern, backwards = case how
228
+ when :case
229
+ [/#{term}/, false]
230
+ when :reverse
231
+ [/#{term.reverse}/i, true]
232
+ when :case_reverse
233
+ [/#{term.reverse}/, true]
234
+ else
235
+ [/#{term}/i, false]
236
+ end
237
+
238
+ position = @text_area.get_selection_start || 0
239
+ contents = @text_area.text
240
+
241
+ if backwards
242
+ contents.reverse!
243
+ position = contents.length - position
244
+ end
245
+
246
+ next_position = contents.index pattern, position + 1
247
+
248
+ if next_position
249
+ next_position =
250
+ contents.length -
251
+ next_position -
252
+ term.length if backwards
253
+
254
+ @text_area.set_selection_start next_position
255
+ @text_area.set_selection_end next_position + term.length
256
+ end
257
+ end
258
+ end
259
+
260
+ if __FILE__ == $0
261
+ JunqueNoteApp.new
262
+ end
@@ -0,0 +1,10 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5
+
6
+ require 'rake'
7
+ require 'rake/testtask'
8
+ require 'rake/rdoctask'
9
+
10
+ require 'tasks/rails'
@@ -0,0 +1,18 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ # Filters added to this controller apply to all controllers in the application.
10
+ # Likewise, all the methods added will be available for all controllers.
11
+
12
+ class ApplicationController < ActionController::Base
13
+ helper :all # include all helpers, all the time
14
+
15
+ # See ActionController::RequestForgeryProtection for details
16
+ # Uncomment the :secret if you're not using the cookie session store
17
+ protect_from_forgery # :secret => '7243747ccf7fcd6980929d8a49f62572'
18
+ end
@@ -0,0 +1,28 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ class GuestsController < ApplicationController
10
+ # POST /guests
11
+ # POST /guests.xml
12
+ def create
13
+ party_permalink = params[:guest].delete :party_permalink
14
+ party = Party.find_by_permalink party_permalink
15
+ @guest = Guest.new(params[:guest].merge :party_id => party.id)
16
+
17
+ respond_to do |format|
18
+ if @guest.save
19
+ flash[:notice] = 'You have successfully RSVPed.'
20
+ format.html { redirect_to(@guest.party) }
21
+ format.xml { render :xml => @guest, :status => :created, :location => @guest }
22
+ else
23
+ format.html { redirect_to(@guest.party) }
24
+ format.xml { render :xml => @guest.errors, :status => :unprocessable_entity }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,77 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ class PartiesController < ApplicationController
10
+ # GET /parties
11
+ def index
12
+ redirect_to new_party_url
13
+ end
14
+
15
+ # GET /parties/1
16
+ # GET /parties/1.xml
17
+ def show
18
+ @party = Party.find_by_permalink(params[:id])
19
+
20
+ guest_name = params[:accept] || params[:decline]
21
+ if guest_name
22
+ guest = Guest.new \
23
+ :party_id => @party.id,
24
+ :name => guest_name,
25
+ :attending => params.has_key?(:accept)
26
+ guest.save
27
+ end
28
+
29
+ respond_to do |format|
30
+ format.html # show.html.erb
31
+ format.xml { render :xml => @party }
32
+ format.text do
33
+ email = PartyMailer.create_invite @party, params[:email]
34
+ render :text => email.encoded
35
+ end
36
+ end
37
+ end
38
+
39
+ # GET /parties/new
40
+ # GET /parties/new.xml
41
+ def new
42
+ @party = Party.new
43
+
44
+ respond_to do |format|
45
+ format.html # new.html.erb
46
+ format.xml { render :xml => @party }
47
+ end
48
+ end
49
+
50
+ # POST /parties
51
+ # POST /parties.xml
52
+ def create
53
+ @party = Party.new(params[:party])
54
+
55
+ respond_to do |format|
56
+ if @party.save
57
+ recipients = params[:recipients]
58
+
59
+ if !recipients || recipients.empty?
60
+ flash[:notice] = 'Paste the text below into your e-mail program.'
61
+ else
62
+ recipients.split(',').each do |address|
63
+ email = PartyMailer.deliver_invite @party, address
64
+ end
65
+
66
+ flash[:notice] = "Invitations successfully sent to #{recipients}."
67
+ end
68
+
69
+ format.html { redirect_to(@party) }
70
+ format.xml { render :xml => @party, :status => :created, :location => @party }
71
+ else
72
+ format.html { render :action => "new" }
73
+ format.xml { render :xml => @party.errors, :status => :unprocessable_entity }
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,11 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ # Methods added to this helper will be available to all templates in the application.
10
+ module ApplicationHelper
11
+ end
@@ -0,0 +1,10 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ module GuestsHelper
10
+ end
@@ -0,0 +1,10 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ module PartiesHelper
10
+ end
@@ -0,0 +1,11 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ class Guest < ActiveRecord::Base
10
+ belongs_to :party
11
+ end
@@ -0,0 +1,32 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ require 'digest/sha1'
10
+
11
+ class Party < ActiveRecord::Base
12
+ has_many :guests
13
+ after_create :assign_permalink
14
+
15
+ def to_param
16
+ permalink
17
+ end
18
+
19
+ def after_initialize
20
+ if new_record?
21
+ self.begins_at ||= Time.now.monday + 5.days + 22.hours
22
+ self.ends_at ||= begins_at + 4.hours
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def assign_permalink
29
+ plaintext = "#{id}-#{Time.now.to_f}-{rand}"
30
+ update_attribute :permalink, Digest::SHA1.hexdigest(plaintext)
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ #---
2
+ # Excerpted from "Scripted GUI Testing With Ruby",
3
+ # published by The Pragmatic Bookshelf.
4
+ # Copyrights apply to this code. It may not be used to create training material,
5
+ # courses, books, articles, and the like. Contact us if you are in doubt.
6
+ # We make no guarantees that this code is fit for any purpose.
7
+ # Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ #---
9
+ class PartyMailer < ActionMailer::Base
10
+ def invite(party, address)
11
+ @subject = "Invitation to #{party.name}"
12
+ @from = 'no-reply@example.com'
13
+ @recipients = address
14
+ @sent_on = Time.now
15
+ @body['party'] = party
16
+ @body['url'] = party_url party, :host => 'localhost:3000'
17
+ @body['address'] = address
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ <!--
2
+ ! Excerpted from "Scripted GUI Testing With Ruby",
3
+ ! published by The Pragmatic Bookshelf.
4
+ ! Copyrights apply to this code. It may not be used to create training material,
5
+ ! courses, books, articles, and the like. Contact us if you are in doubt.
6
+ ! We make no guarantees that this code is fit for any purpose.
7
+ ! Visit http://www.pragmaticprogrammer.com/titles/idgtr for more book information.
8
+ -->
9
+ <html>
10
+ <head>
11
+ <title>novite - hassle-free invites</title>
12
+ <style>
13
+ body {
14
+ font-family: "Frutiger", "Univers", "Helvetica Neue", arial, helvetica, sans-serif;
15
+ }
16
+
17
+ ul {
18
+ list-style-image: none;
19
+ list-style-type: none;
20
+ margin-left: 0px;
21
+ padding-left: 0px;
22
+ }
23
+
24
+ ul li {
25
+ margin-bottom: 5px;
26
+ }
27
+
28
+ span.drag {
29
+ background-color: black;
30
+ color: white;
31
+ cursor: move;
32
+ padding: 1px;
33
+ font-size: small;
34
+ }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <% if flash[:notice] %>
39
+ <div id="party_notice"><%= flash[:notice] %></div>
40
+ <% end %>
41
+
42
+ <%= yield %>
43
+ </body>
44
+ </html>
@@ -0,0 +1,42 @@
1
+ <h1>New party</h1>
2
+
3
+ <%= error_messages_for :party %>
4
+
5
+ <% form_for(@party) do |f| %>
6
+ <p>
7
+ <h3>What:</h3>
8
+ <%= f.text_field :name %>
9
+ </p>
10
+
11
+ <p>
12
+ <h3>Why:</h3>
13
+ <%= f.text_area :description, :rows => 5 %>
14
+ </p>
15
+
16
+ <p>
17
+ <h3>Where:</h3>
18
+ <%= f.text_area :location, :rows => 5 %>
19
+ </p>
20
+
21
+ <p>
22
+ <h3>When:</h3>
23
+ <h3>From</b><br />
24
+ <%= f.datetime_select :begins_at %>
25
+ </p>
26
+
27
+ <p>
28
+ <b>to</b><br />
29
+ <%= f.datetime_select :ends_at %>
30
+ </p>
31
+
32
+ <p>
33
+ <h3>Who:</h3>
34
+ <textarea name="recipients" id="party_recipients" rows="5" cols="40"></textarea>
35
+ </p>
36
+
37
+ <p>
38
+ <%= f.submit "Create" %>
39
+ </p>
40
+ <% end %>
41
+
42
+ <%= link_to 'Back', parties_path %>
@@ -0,0 +1,43 @@
1
+ <h1>Invitation to <%=h @party.name %></h1>
2
+
3
+ <p>
4
+ You're invited to <span id="party_name"><%=h @party.name %></span>
5
+ on <span id="party_begins_on"><%=h @party.begins_at.strftime '%A, %B %d, %Y' %></span>,
6
+ from <span id="party_begins_at"><%=h @party.begins_at.strftime '%I:%M %p' %></span>
7
+ to <span id="party_ends_at"><%=h @party.ends_at.strftime '%I:%M %p' %></span>!
8
+ </p>
9
+
10
+ <p>
11
+ There are many parties, but only this one lives at:
12
+ <br /><%= link_to party_url(@party), {}, :id => 'party_link' %>
13
+ </p>
14
+
15
+ <h2>Details</h2>
16
+
17
+ <p>
18
+ <b>Why:</b>
19
+ <span id="party_description"/><%=h @party.description %></span>
20
+ </p>
21
+
22
+ <p>
23
+ <b>Where:</b>
24
+ <span id="party_location"><%=h @party.location %></span>
25
+ </p>
26
+
27
+ <p>
28
+ <b>Who:</b>
29
+ <% form_for :guest, :url => guests_url do |f| %>
30
+ <%= f.hidden_field :party_permalink, :value => @party.permalink %>
31
+ <%= f.text_field :name %>
32
+ <%= f.check_box :attending, :checked => true %>
33
+ attending
34
+ <%= submit_tag 'RSVP', :id => 'rsvp' %>
35
+ <% end %>
36
+
37
+ <ul id="guests">
38
+ <% @party.guests.each do |rsvp| %>
39
+ <li><span class="rsvp_name"><%=h rsvp.name %></span>
40
+ is <span class="rsvp_attending"><%= rsvp.attending ? 'attending' : 'not attending' %></span></li>
41
+ <% end %>
42
+ </ul>
43
+ </p>
@@ -0,0 +1,17 @@
1
+ Invitation to <%=h @party.name %>
2
+
3
+ You're invited to <%=h @party.name %> on <%=h @party.begins_at.strftime '%A, %B %d, %Y' %>, from <%=h @party.begins_at.strftime '%I:%M %p' %> to <%=h @party.ends_at.strftime '%I:%M %p' %>!
4
+
5
+ You can RSVP by visiting <%= @url %>, or clicking one of the RSVP links below.
6
+
7
+ Details
8
+
9
+ Why:
10
+ <%=h @party.description %>
11
+
12
+ Where:
13
+ <%=h @party.location %>
14
+
15
+ RSVP:
16
+ Yes - <%= @url %>?accept=<%= CGI::escape @address %>
17
+ No - <%= @url %>?decline=<%= CGI::escape @address %>