rwdaddresses 1.01 → 1.02

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/Readme.txt +5 -0
  2. data/code/01rwdcore/01rwdcore.rb +15 -13
  3. data/code/01rwdcore/openhelpwindow.rb +26 -26
  4. data/code/01rwdcore/returntomain.rb +8 -8
  5. data/code/01rwdcore/rwdtinkerversion.rb +12 -13
  6. data/code/01rwdcore/rwdwindowreturn.rb +3 -5
  7. data/code/01rwdcore/test_cases.rb +115 -0
  8. data/code/01rwdcore/test_harness.rb +12 -0
  9. data/code/01rwdcore/uploadreturns.rb +60 -59
  10. data/code/superant.com.rwdaddresses/attachtmpcontactphoto.rb +23 -23
  11. data/code/superant.com.rwdaddresses/clearscreendisplay.rb +14 -15
  12. data/code/superant.com.rwdaddresses/createnewnamerecord.rb +19 -18
  13. data/code/superant.com.rwdaddresses/deletecontactrecord.rb +22 -21
  14. data/code/superant.com.rwdaddresses/deleterwdaddressesupdatefiles.rb +15 -16
  15. data/code/superant.com.rwdaddresses/downloadrwdaddressfiles.rb +34 -32
  16. data/code/superant.com.rwdaddresses/listnamerecord.rb +14 -14
  17. data/code/superant.com.rwdaddresses/listvcardrecord.rb +15 -0
  18. data/code/superant.com.rwdaddresses/loadconfigurationrecord.rb +45 -44
  19. data/code/superant.com.rwdaddresses/loadconfigurationvariables.rb +14 -13
  20. data/code/superant.com.rwdaddresses/loadnamerecord.rb +29 -29
  21. data/code/superant.com.rwdaddresses/openhelpwindowrwdaddresses.rb +25 -25
  22. data/code/superant.com.rwdaddresses/renamecontact.rb +14 -15
  23. data/code/superant.com.rwdaddresses/returntomain.rb +8 -8
  24. data/code/superant.com.rwdaddresses/runaddresseswindow.rb +8 -8
  25. data/code/superant.com.rwdaddresses/runrwdaddressesmenu1.rb +31 -31
  26. data/code/superant.com.rwdaddresses/runrwdaddresssyncbackwindow.rb +8 -8
  27. data/code/superant.com.rwdaddresses/rwdaddressesbackwindow.rb +8 -8
  28. data/code/superant.com.rwdaddresses/rwdaddresseshelpabout.rb +10 -11
  29. data/code/superant.com.rwdaddresses/saveconfigurationrecord.rb +20 -20
  30. data/code/superant.com.rwdaddresses/savevcardrecord.rb +76 -0
  31. data/code/superant.com.rwdaddresses/syncrwdaddress.rb +24 -26
  32. data/code/superant.com.rwdaddresses/uploadrwdaddressfiles.rb +28 -28
  33. data/code/superant.com.rwdaddresses/viewaddressconfiguration.rb +21 -21
  34. data/code/superant.com.rwdaddresses/viewnamedata.rb +27 -26
  35. data/code/superant.com.rwdaddresses/viewphoto.rb +4 -4
  36. data/code/superant.com.rwdaddresses/viewrwdaddressesconfiguration.rb +23 -21
  37. data/code/superant.com.rwdaddresses/viewtmpcontactphoto.rb +6 -6
  38. data/code/superant.com.rwdaddresses/viewvcarddata.rb +22 -0
  39. data/code/superant.com.rwdtinkerbackwindow/controlclient.rb +89 -92
  40. data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +15 -20
  41. data/code/superant.com.rwdtinkerbackwindow/installapplet.rb +19 -18
  42. data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +20 -19
  43. data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +19 -18
  44. data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +7 -7
  45. data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +48 -49
  46. data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +8 -7
  47. data/code/superant.com.rwdtinkerbackwindow/listzips.rb +22 -26
  48. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +32 -31
  49. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -13
  50. data/code/superant.com.rwdtinkerbackwindow/network.rb +82 -82
  51. data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +18 -17
  52. data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +37 -37
  53. data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +20 -20
  54. data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +33 -32
  55. data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +8 -9
  56. data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +10 -11
  57. data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -18
  58. data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +21 -20
  59. data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +23 -20
  60. data/configuration/language.dist +1 -1
  61. data/configuration/rwdaddresses.dist +2 -2
  62. data/configuration/rwdtinker.dist +2 -2
  63. data/configuration/tinkerwin2variables.dist +1 -1
  64. data/extras/vpim/date.rb +198 -0
  65. data/extras/vpim/dirinfo.rb +229 -0
  66. data/extras/vpim/enumerator.rb +29 -0
  67. data/extras/vpim/field.rb +497 -0
  68. data/extras/vpim/maker/vcard.rb +312 -0
  69. data/extras/vpim/rfc2425.rb +244 -0
  70. data/extras/vpim/rrule.rb +482 -0
  71. data/extras/vpim/time.rb +42 -0
  72. data/extras/vpim/vcard.rb +151 -0
  73. data/extras/vpim/vpim.rb +94 -0
  74. data/gui/frontwindow0/superant.com.rwdaddresses/16editrecord.rwd +5 -0
  75. data/gui/frontwindow0/superant.com.rwdaddresses/17viewvcardrecord.rwd +32 -0
  76. data/gui/helpaboutinstalled/superant.com.tinkerhelpabout/3copyright.rwd +1 -1
  77. data/gui/tinkerbackwindows/superant.com.rwdaddressessyncbackwindow/70rwddiagnostics.rwd +1 -11
  78. data/init.rb +231 -228
  79. data/names/Angelina Jolie.vcf +8 -0
  80. data/rwd_files/HowTo_Addresses.txt +5 -0
  81. data/rwd_files/HowTo_Tinker.txt +14 -0
  82. data/rwdconfig.dist +6 -2
  83. data/tests/makedist.rb +36 -7
  84. metadata +23 -21
  85. data/extras/cmdline_parse +0 -47
  86. data/extras/config_file +0 -69
  87. data/extras/errorMsg +0 -19
  88. data/extras/makePlaylist +0 -34
  89. data/extras/mp3controld +0 -289
  90. data/extras/playlist +0 -186
  91. data/extras/plugins/Network +0 -237
  92. data/extras/showHelp +0 -18
  93. data/gui/frontwindowselections/superant.com.rwdaddressesselectiontab/rwdaddressessyncselectiontab.rwd +0 -12
  94. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/1appname.rwd +0 -4
  95. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/3copyright.rwd +0 -3
  96. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/5version.rwd +0 -10
  97. data/installed/rwdaddressesdata2.inf +0 -8
  98. data/rwd_files/tinker.png +0 -0
@@ -1,24 +1,24 @@
1
1
  # This tinker method is to retrieve the list of rwdzip applets available to install from the remote repository
2
-
3
2
  def superantcomremotegemlist
4
- gemcommandoption = "search --remote "
5
- gemfilename = "rwdzip"
6
- commandtext = "gem search --remote rwdzip"
7
- commandtemp = $xpcommand + commandtext
8
- begin # exception trapped block
9
-
10
- tempremotegemappletsresult = `#{commandtemp} 2>&1`
11
- @superantcomremotegemappletsfullresult = tempremotegemappletsresult
12
- fileList = tempremotegemappletsresult.split(/\n/).delete_if { |x| ! (x =~ /\Arwdzip/) }
13
-
14
- @superantcomremotegemappletsresult = fileList.rwd_method("superantcomremotegemappletdirsname")
15
- rescue SystemCallError, StandardError
16
- @superantcomremotegemappletsresult = "system call error: " + $!
17
- end # exception rescue
3
+ gemcommandoption = "search --remote "
4
+ gemfilename = "rwdzip"
5
+ commandtext = "gem search --remote rwdzip"
6
+ commandtemp = $xpcommand + commandtext
7
+ begin # exception trapped block
8
+
9
+ tempremotegemappletsresult = `#{commandtemp} 2>&1`
10
+ @superantcomremotegemappletsfullresult = tempremotegemappletsresult
11
+ fileList = tempremotegemappletsresult.split(/\n/).delete_if { |x| ! (x =~ /\Arwdzip/) }
12
+
13
+ @superantcomremotegemappletsresult = fileList.rwd_method("superantcomremotegemappletdirsname")
14
+ rescue SystemCallError, StandardError
15
+ @superantcomremotegemappletsresult = "system call error: " + $!
16
+ end # exception rescue
18
17
  end
19
-
18
+
20
19
  def superantcomremotegemappletdirsname(inffile)
21
- applet = inffile
22
- @superantcominstallremoteappletinput = applet
23
-
24
- end
20
+ applet = inffile
21
+ @superantcominstallremoteappletinput = applet
22
+
23
+ end
24
+
@@ -1,32 +1,33 @@
1
- def removeapplet
2
- require 'fileutils'
3
- nametext = "%s" % [@a_removeapplet]
4
-
5
- begin # exception trapped block
6
- fileName = "installed/" + nametext + ".inf"
7
- count = 0
8
- fd = File.open(fileName,"r")
9
-
10
-
11
- fd.each { |oneline|
12
- if count == 1
13
- if File.exist?(oneline.chop)
14
- FileUtils.rm_rf( oneline.chop)
15
- end
16
-
17
- end
18
- count = 1
19
- }
20
- fd.close
21
-
22
- FileUtils.rm_rf( fileName)
23
-
24
-
25
- @removeapplettext = "applet files removed! - restart rwd to finish uninstalling"
26
-
27
- rescue
28
- @removeapplettext = "\n" + "error"
29
-
30
- end # exception rescue
31
-
32
- end
1
+ # method to remove a tinker applet
2
+ def removeapplet
3
+ require 'fileutils'
4
+ nametext = "%s" % [@a_removeapplet]
5
+
6
+ begin # exception trapped block
7
+ fileName = "installed/" + nametext + ".inf"
8
+ count = 0
9
+ fd = File.open(fileName,"r")
10
+
11
+
12
+ fd.each { |oneline|
13
+ if count == 1
14
+ if File.exist?(oneline.chop)
15
+ FileUtils.rm_rf( oneline.chop)
16
+ end
17
+
18
+ end
19
+ count = 1
20
+ }
21
+ fd.close
22
+
23
+ FileUtils.rm_rf( fileName)
24
+
25
+
26
+ @removeapplettext = "applet files removed! - restart rwd to finish uninstalling"
27
+
28
+ rescue
29
+ @removeapplettext = "\n" + "error"
30
+
31
+ end # exception rescue
32
+
33
+ end
@@ -1,12 +1,11 @@
1
1
  # Application RwdTinker orginally (c) 2004 Steven Gibson under GPL.
2
2
  # This application is a framework for writing programs from RubyWebDialogs
3
- # http://www.erikveen.dds.nl/rubywebdialogs/index.html
4
- # For more information about RwdTinker see http://www.rubyforge.net/projects/rwdapplications
5
-
6
- # call the rwdtinker helpwindow
3
+ # For information see http://www.rubyforge.net/projects/rwdapplications
4
+
5
+ # call the rwdtinker helpwindow
6
+
7
+ def runrwdtinkerbackwindow
8
+ @rwd_window = "tinkerbackwindow"
9
+ @rwd_tab = "rwdzipslister"
10
+ end
7
11
 
8
- def runrwdtinkerbackwindow
9
- @rwd_window = "tinkerbackwindow"
10
- @rwd_tab = "rwdzipslister"
11
- end
12
-
@@ -1,14 +1,13 @@
1
1
  # Application RwdTinker orginally (c) 2004 Steven Gibson under GPL.
2
2
  # This application is a framework for writing programs from RubyWebDialogs
3
- # http://www.erikveen.dds.nl/rubywebdialogs/index.html
4
- # For more information about RwdTinker see http://www.rubyforge.net/projects/rwdapplications
5
-
6
- # return the version constant defined in the config file
7
- def runrwdtinkerwin2version
8
- @rwd_window = "applicationversion"
9
- @versionappnamedisplay = "RwdTinkerWin2"
10
- @versioncopyrightdisplay = "(c) 2004 Steven Gibson "
11
- @versionnumberdisplay = "Version " + RwdTinkerWin2Version
3
+ # For information see http://www.rubyforge.net/projects/rwdapplications
4
+
5
+ # return the version constant defined in the config file
6
+ def runrwdtinkerwin2version
7
+ @rwd_window = "applicationversion"
8
+ @versionappnamedisplay = "RwdTinkerWin2"
9
+ @versioncopyrightdisplay = "(c) 2004 Steven Gibson "
10
+ @versionnumberdisplay = "Version " + RwdTinkerWin2Version
11
+
12
+ end
12
13
 
13
- end
14
-
@@ -1,18 +1,19 @@
1
- # this method saves the configuration record
2
- def saveconfigurationrecord
3
- require 'fileutils'
4
- if @a_configurationfilename
5
- newname = "%s" % [@a_configurationfilename] # grab the filename to create
6
- newdata =@a_configline1.to_s + "\n" + @a_configline2.to_s + "\n" + @a_configline3.to_s + "\n" + @a_configline4.to_s + "\n" + @a_configline5.to_s + "\n" + @a_configline6.to_s + "\n" + @a_configline7.to_s + "\n" + @a_configline8.to_s + "\n"
7
-
8
- begin # exception trapped block
9
- fileName = File.join( ConfigurationDir, newname )
10
- fd = File.open(fileName,"w")
11
- fd.print(newdata) # save the record info to the file
12
- fd.close
13
- @newconfigurationresult=newdata # show the record info in the browser
14
- rescue SystemCallError, StandardError
15
- $stderr.print "system call error: " + $!
16
- end # exception rescue
17
- end
18
- end
1
+ # this method saves the configuration record
2
+ def saveconfigurationrecord
3
+ require 'fileutils'
4
+ if @a_configurationfilename
5
+ newname = "%s" % [@a_configurationfilename] # grab the filename to create
6
+ newdata =@a_configline1.to_s + "\n" + @a_configline2.to_s + "\n" + @a_configline3.to_s + "\n" + @a_configline4.to_s + "\n" + @a_configline5.to_s + "\n" + @a_configline6.to_s + "\n" + @a_configline7.to_s + "\n" + @a_configline8.to_s + "\n"
7
+
8
+ begin # exception trapped block
9
+ fileName = File.join( ConfigurationDir, newname )
10
+ fd = File.open(fileName,"w")
11
+ fd.print(newdata) # save the record info to the file
12
+ fd.close
13
+ @newconfigurationresult=newdata # show the record info in the browser
14
+ rescue SystemCallError, StandardError
15
+ $stderr.print "system call error: " + $!
16
+ end # exception rescue
17
+ end
18
+ end
19
+
@@ -1,21 +1,22 @@
1
- def viewappletcontents
2
- require 'fileutils'
3
- require 'extras/zip/zip'
4
- nametext = "%s" % [@a_installapplet]
5
-
6
- begin # exception trapped block
7
- fullname = nametext + ".zip"
8
- fileName = File.join($zipslocation,fullname)
9
- tempfilecontents = " "
10
- zf = Zip::ZipFile.new(fileName)
11
- zf.sort.each {
12
- |entry|
13
- tempfilecontents = tempfilecontents + entry.to_s + "\n"
14
- }
15
- @appletcontentstext = tempfilecontents
16
-
17
- rescue
18
- @installapplettext = "unzip error - error opening applet"
19
- end # exception rescue
1
+ #view contents of a tinker applet
2
+ def viewappletcontents
3
+ require 'fileutils'
4
+ require 'extras/zip/zip'
5
+ nametext = "%s" % [@a_installapplet]
20
6
 
21
- end
7
+ begin # exception trapped block
8
+ fullname = nametext + ".zip"
9
+ fileName = File.join($zipslocation,fullname)
10
+ tempfilecontents = " "
11
+ zf = Zip::ZipFile.new(fileName)
12
+ zf.sort.each {
13
+ |entry|
14
+ tempfilecontents = tempfilecontents + entry.to_s + "\n"
15
+ }
16
+ @appletcontentstext = tempfilecontents
17
+
18
+ rescue
19
+ @installapplettext = "unzip error - error opening applet"
20
+ end # exception rescue
21
+
22
+ end
@@ -1,21 +1,24 @@
1
- def viewgemappletcontents
2
- require 'fileutils'
3
- require 'extras/zip/zip'
4
- nametext = "%s" % [@a_installapplet]
5
-
6
- begin # exception trapped block
7
- fullname = nametext + ".zip"
8
-
9
- tempfilecontents = " "
10
- zf = Zip::ZipFile.new(fullname)
11
- zf.sort.each {
12
- |entry|
13
- tempfilecontents = tempfilecontents + entry.to_s + "\n"
14
- }
15
- @appletcontentstext = tempfilecontents
16
-
17
- rescue
18
- @installapplettext = "unzip error - error opening applet"
19
- end # exception rescue
1
+ #view gem info
2
+ def viewgemappletcontents
3
+ require 'fileutils'
4
+ require 'extras/zip/zip'
5
+ nametext = "%s" % [@a_installapplet]
6
+
7
+ begin # exception trapped block
8
+ fullname = nametext + ".zip"
9
+
10
+ tempfilecontents = " "
11
+ zf = Zip::ZipFile.new(fullname)
12
+ zf.sort.each {
13
+ |entry|
14
+ tempfilecontents = tempfilecontents + entry.to_s + "\n"
15
+ }
16
+ @appletcontentstext = tempfilecontents
17
+
18
+ rescue
19
+ @installapplettext = "unzip error - error opening applet"
20
+ end # exception rescue
21
+
22
+ end
23
+
20
24
 
21
- end
@@ -1,4 +1,4 @@
1
- ##VERSION:1.57
1
+ ##VERSION:1.62
2
2
  #language selection file
3
3
  ##NAME:$lang:0
4
4
  #$lang = "jp"
@@ -1,4 +1,4 @@
1
- ##VERSION:1.01
1
+ ##VERSION:1.02
2
2
  #rwdaddresses contact book
3
3
  $photodelay = 1
4
4
  ##NAME:$addressfiles_directory:0
@@ -16,4 +16,4 @@ $rwdaddresses_ftpdirectory = "/incoming/rwdnames/"
16
16
  ##NAME:$rwdaddresses_updatedirectory:0
17
17
  $rwdaddresses_updatedirectory = "updates"
18
18
 
19
- RwdAddressesVersion = "1.01"
19
+ RwdAddressesVersion = "1.02"
@@ -1,4 +1,4 @@
1
- ##VERSION:1.59
1
+ ##VERSION:1.62
2
2
  ConfigurationDir = "configuration" # for use in program - init.rb has this value without using this constant
3
3
  CodeName = "rwdtinker"
4
4
  CodeNameFile = CodeName + ".rb"
@@ -12,4 +12,4 @@ LangDir = "lang"
12
12
  $rwdcontrolports =["13713","13714","13715","13716","13717","13718"]
13
13
  $port = 7705
14
14
 
15
- RwdTinkerVersion = "1.59"
15
+ RwdTinkerVersion = "1.62"
@@ -1,4 +1,4 @@
1
- ##VERSION:1.57
1
+ ##VERSION:1.62
2
2
  TinkerWin2ConfigurationFileName = "tinkerwin2variables.cnf" # this file name - do not change
3
3
  ##NAME:$zipslocation:0
4
4
  $zipslocation = "zips" # location of applets to add
@@ -0,0 +1,198 @@
1
+ =begin
2
+ $Id: date.rb,v 1.8 2004/11/17 05:06:27 sam Exp $
3
+
4
+ Copyright (C) 2005 Sam Roberts
5
+
6
+ This library is free software; you can redistribute it and/or modify it
7
+ under the same terms as the ruby language itself, see the file COPYING for
8
+ details.
9
+ =end
10
+
11
+ require 'date'
12
+
13
+ # Extensions to the standard library Date.
14
+ class Date
15
+
16
+ TIME_START = Date.new(1970, 1, 1)
17
+ SECS_PER_DAY = 24 * 60 * 60
18
+
19
+ # Converts this object to a Time object, or throws an ArgumentError if
20
+ # conversion is not possible because it is before the start of epoch.
21
+ def to_time
22
+ raise ArgumentError, 'date is before the start of system time' if self < TIME_START
23
+ days = self - TIME_START
24
+
25
+ Time.at((days * SECS_PER_DAY).to_i)
26
+ end
27
+
28
+ # If wday responds to to_str, convert it to the wday number by searching for
29
+ # a wday that matches, using as many characters as are in wday to do the
30
+ # comparison. wday must be 2 or more characters long in order to be a unique
31
+ # match, other than that, "mo", "Mon", and "MonDay" are all valid strings
32
+ # for wday 1.
33
+ #
34
+ # This method can be called on a valid wday, and it will return it. Perhaps
35
+ # it should be called by default inside the Date#new*() methods so that
36
+ # non-integer wday arguments can be used? Perhaps a similar method should
37
+ # exist for months? But with months, we all know January is 1, who can
38
+ # remember where Date chooses to start its wday count!
39
+ #
40
+ # Examples:
41
+ # Date.bywday(2004, 2, Date.str2wday('TU')) => the first Tuesday in
42
+ # February
43
+ # Date.bywday(2004, 2, Date.str2wday(2)) => the same day, but notice
44
+ # that a valid wday integer can be passed right through.
45
+ #
46
+ def Date.str2wday(wdaystr)
47
+ return wdaystr unless wdaystr.respond_to? :to_str
48
+
49
+ str = wdaystr.to_str.upcase
50
+ if str.length < 2
51
+ raise ArgumentError, 'wday #{wday} is not long enough to be a unique weekday name'
52
+ end
53
+
54
+ wday = Date::DAYNAMES.map { |n| n.slice(0, str.length).upcase }.index(str)
55
+
56
+ return wday if wday
57
+
58
+ raise ArgumentError, 'wday #{wdaystr} was not a recognizable weekday name'
59
+ end
60
+
61
+
62
+ # Create a new Date object for the date specified by year +year+, month
63
+ # +mon+, and day-of-the-week +wday+.
64
+ #
65
+ # The nth, +n+, occurrence of +wday+ within the period will be generated
66
+ # (+n+ defaults to 1). If +n+ is positive, the nth occurence from the
67
+ # beginning of the period will be returned, if negative, the nth occurrence
68
+ # from the end of the period will be returned.
69
+ #
70
+ # The period is a year, unless +month+ is non-nil, in which case it is just
71
+ # that month.
72
+ #
73
+ # Examples:
74
+ # - Date.bywday(2004, nil, 1, 9) => the ninth Sunday of 2004
75
+ # - Date.bywday(2004, nil, 1) => the first Sunday of 2004
76
+ # - Date.bywday(2004, nil, 1, -2) => the second last Sunday of 2004
77
+ # - Date.bywday(2004, 12, 1) => the first sunday in the 12th month of 2004
78
+ # - Date.bywday(2004, 2, 2, -1) => last Tuesday in the 2nd month in 2004
79
+ # - Date.bywday(2004, -2, 3, -2) => second last Wednesday in the second last month of 2004
80
+ #
81
+ # Compare this to Date.new, which allows a Date to be created by
82
+ # day-of-the-month, mday, to Date.new2, which allows a Date to be created by
83
+ # day-of-the-year, yday, and to Date.neww, which allows a Date to be created
84
+ # by day-of-the-week, but within a specific week.
85
+ def Date.bywday(year, mon, wday, n = 1, sg=Date::ITALY)
86
+ # Normalize mon to 1-12.
87
+ if mon
88
+ if mon > 12 || mon == 0 || mon < -12
89
+ raise ArgumentError, "mon #{mon} must be 1-12 or negative 1-12"
90
+ end
91
+ if mon < 0
92
+ mon = 13 + mon
93
+ end
94
+ end
95
+ if wday < 0 || wday > 6
96
+ raise ArgumentError, 'wday must be in range 0-6, or a weekday name'
97
+ end
98
+
99
+ # Determine direction of indexing.
100
+ inc = n <=> 0
101
+ if inc == 0
102
+ raise ArgumentError, 'n must be greater or less than zero'
103
+ end
104
+
105
+ # if !mon, n is index into year, but direction of search is determined by
106
+ # sign of n
107
+ d = Date.new(year, mon ? mon : inc, inc, sg)
108
+
109
+ while d.wday != wday
110
+ d += inc
111
+ end
112
+
113
+ # Now we have found the first/last day with the correct wday, search
114
+ # for nth occurrence, by jumping by n.abs-1 weeks forward or backward.
115
+ d += 7 * (n.abs - 1) * inc
116
+
117
+ if d.year != year
118
+ raise ArgumentError, 'n is out of bounds of year'
119
+ end
120
+ if mon && d.mon != mon
121
+ raise ArgumentError, 'n is out of bounds of month'
122
+ end
123
+ d
124
+ end
125
+ end
126
+
127
+ # DateGen generates arrays of dates matching simple criteria.
128
+ class DateGen
129
+ # Generate an array of dates on +wday+ (the day-of-week,
130
+ # 0-6, where 0 is Sunday).
131
+ #
132
+ # If +n+ is specified, only the nth occurrence of +wday+ within the period
133
+ # will be generated. If +n+ is positive, the nth occurence from the
134
+ # beginning of the period will be returned, if negative, the nth occurrence
135
+ # from the end of the period will be returned.
136
+ #
137
+ # The period is a year, unless +month+ is non-nil, in which case it is just
138
+ # that month.
139
+ #
140
+ # Examples:
141
+ # - DateGen.bywday(2004, nil, 1, 9) => the ninth Sunday in 2004
142
+ # - DateGen.bywday(2004, nil, 1) => all Sundays in 2004
143
+ # - DateGen.bywday(2004, nil, 1, -2) => second last Sunday in 2004
144
+ # - DateGen.bywday(2004, 12, 1) => all sundays in December 2004
145
+ # - DateGen.bywday(2004, 2, 2, -1) => last Tuesday in February in 2004
146
+ # - DateGen.bywday(2004, -2, 3, -2) => second last Wednesday in November of 2004
147
+ #
148
+ # Compare to Date.bywday(), which allows a single Date to be created with
149
+ # similar criteria.
150
+ def DateGen.bywday(year, month, wday, n = nil)
151
+ seed = Date.bywday(year, month, wday, n ? n : 1)
152
+
153
+ dates = [ seed ]
154
+
155
+ return dates if n
156
+
157
+ succ = seed.clone
158
+
159
+ # Collect all matches until we're out of the year (or month, if specified)
160
+ loop do
161
+ succ += 7
162
+
163
+ break if succ.year != year
164
+ break if month && succ.month != seed.month
165
+
166
+ dates.push succ
167
+ end
168
+ dates.sort!
169
+ dates
170
+ end
171
+
172
+ # Generate an array of dates on +mday+ (the day-of-month, 1-31). For months
173
+ # in which the +mday+ is not present, no date will be generated.
174
+ #
175
+ # The period is a year, unless +month+ is non-nil, in which case it is just
176
+ # that month.
177
+ #
178
+ # Compare to Date.new(), which allows a single Date to be created with
179
+ # similar criteria.
180
+ def DateGen.bymonthday(year, month, mday)
181
+ months = month ? [ month ] : 1..12
182
+ dates = [ ]
183
+
184
+ months.each do |m|
185
+ begin
186
+ dates << Date.new(year, m, mday)
187
+ rescue ArgumentError
188
+ # Don't generate dates for invalid combinations (Feb 29, when it's not
189
+ # a leap year, for example).
190
+ #
191
+ # TODO - should we raise when month is out of range, or mday can never
192
+ # be in range (32)?
193
+ end
194
+ end
195
+ dates
196
+ end
197
+ end
198
+