chronos 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 (54) hide show
  1. data/CHANGELOG.rdoc +27 -0
  2. data/HISTORY.rdoc +4 -0
  3. data/LICENSE.txt +52 -0
  4. data/MANIFEST.txt +51 -0
  5. data/NOTES.rdoc +85 -0
  6. data/README.rdoc +125 -0
  7. data/Rakefile +34 -0
  8. data/TODO.rdoc +63 -0
  9. data/bench/completebench.rb +24 -0
  10. data/ext/cchronos/extconf.rb +5 -0
  11. data/ext/chronos_core/extconf.rb +5 -0
  12. data/lib/chronos.rb +208 -0
  13. data/lib/chronos/calendar.rb +16 -0
  14. data/lib/chronos/calendar/gregorian.rb +94 -0
  15. data/lib/chronos/data/zones.tab +424 -0
  16. data/lib/chronos/datetime.rb +299 -0
  17. data/lib/chronos/datetime/gregorian.rb +698 -0
  18. data/lib/chronos/duration.rb +141 -0
  19. data/lib/chronos/duration/gregorian.rb +261 -0
  20. data/lib/chronos/durationtotext.rb +42 -0
  21. data/lib/chronos/exceptions.rb +16 -0
  22. data/lib/chronos/gregorian.rb +27 -0
  23. data/lib/chronos/interval.rb +132 -0
  24. data/lib/chronos/interval/gregorian.rb +80 -0
  25. data/lib/chronos/locale/parsers/de_CH.rb +50 -0
  26. data/lib/chronos/locale/parsers/en_US.rb +1 -0
  27. data/lib/chronos/locale/parsers/generic.rb +21 -0
  28. data/lib/chronos/locale/strings/de_DE.yaml +76 -0
  29. data/lib/chronos/locale/strings/en_US.yaml +76 -0
  30. data/lib/chronos/minimalistic.rb +37 -0
  31. data/lib/chronos/numeric/gregorian.rb +100 -0
  32. data/lib/chronos/ruby.rb +6 -0
  33. data/lib/chronos/version.rb +21 -0
  34. data/lib/chronos/zone.rb +212 -0
  35. data/rake/initialize.rb +116 -0
  36. data/rake/lib/assesscode.rb +59 -0
  37. data/rake/lib/bonesplitter.rb +245 -0
  38. data/rake/lib/projectclass.rb +69 -0
  39. data/rake/tasks/copyright.rake +24 -0
  40. data/rake/tasks/gem.rake +119 -0
  41. data/rake/tasks/git.rake +40 -0
  42. data/rake/tasks/loc.rake +33 -0
  43. data/rake/tasks/manifest.rake +63 -0
  44. data/rake/tasks/meta.rake +16 -0
  45. data/rake/tasks/notes.rake +36 -0
  46. data/rake/tasks/post_load.rake +18 -0
  47. data/rake/tasks/rdoc.rake +73 -0
  48. data/rake/tasks/rubyforge.rake +67 -0
  49. data/rake/tasks/spec.rake +55 -0
  50. data/spec/bacon_helper.rb +43 -0
  51. data/spec/lib/chronos/datetime/gregorian_spec.rb +314 -0
  52. data/spec/lib/chronos/datetime_spec.rb +219 -0
  53. data/spec/lib/chronos_spec.rb +91 -0
  54. metadata +111 -0
@@ -0,0 +1,59 @@
1
+ #--
2
+ # Copyright 2007-2008 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ class AssessCode
10
+ def initialize(base, *paths)
11
+ @base = base
12
+ @paths = paths
13
+ reset
14
+ end
15
+
16
+ def reset
17
+ @loc_code = 0
18
+ @loc_comment = 0
19
+ @bytes_code = 0
20
+ @bytes_comment = 0
21
+ @bytes_data = 0
22
+ @files = 0
23
+ end
24
+
25
+ def assess
26
+ reset
27
+ @paths.each { |path|
28
+ assess_dir("#{@base}/#{path}")
29
+ }
30
+ end
31
+
32
+ def assess_dir(dir)
33
+ Dir.glob(dir, &method(:assess_file))
34
+ end
35
+
36
+ def assess_file(file)
37
+ comment = false
38
+ @bytes_data += File.size(file)
39
+ @files += 1
40
+ File.readlines(file).each do |line|
41
+ comment = true if line =~ /^=begin/
42
+ comment = false if line =~ /^=end/
43
+ if comment or line =~ /^\s*(?:#|$)/
44
+ @loc_comment += 1
45
+ @bytes_comment += line.strip.size
46
+ else
47
+ @loc_code += 1
48
+ @bytes_code += line.strip.size
49
+ end
50
+ end
51
+ end
52
+
53
+ def put_assessment
54
+ assess
55
+ puts "#{@bytes_data.div(1024)} KB total data in #{@files} files"
56
+ puts "#{@loc_code} Lines of Code (#{@bytes_code.div(1024)} KB)"
57
+ puts "#{@loc_comment} Lines of Comment (#{@bytes_comment.div(1024)} KB)"
58
+ end
59
+ end # class AssessCode
@@ -0,0 +1,245 @@
1
+ #--
2
+ # Copyright 2007-2008 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'stringio'
10
+ require 'ostruct'
11
+
12
+
13
+
14
+ # fix pre-rubygems 1.3 nuisance
15
+ begin
16
+ require 'rubygems'
17
+ module Kernel
18
+ private :gem
19
+ private :require
20
+ private :open
21
+ end
22
+ rescue LoadError; end
23
+
24
+ # needed for has_version?
25
+ class Array
26
+ include Comparable
27
+ end
28
+
29
+ # The module BoneSplitter offers various helpful methods for rake tasks.
30
+ #
31
+ module BoneSplitter
32
+ def self.find_executable(*names)
33
+ path = ENV["PATH"].split(File::PATH_SEPARATOR)
34
+ names.each { |name|
35
+ found = path.map { |path| File.join(path, name) }.find { |e| File.executable?(e) }
36
+ return found if found
37
+ }
38
+ nil
39
+ end
40
+
41
+ @libs = {}
42
+ @bin = OpenStruct.new(
43
+ :diff => find_executable('diff', 'gdiff', 'diff.exe'),
44
+ :sudo => find_executable('sudo'),
45
+ :rcov => find_executable('rcov', 'rcov.bat'),
46
+ :rdoc => find_executable('rdoc', 'rdoc.bat'),
47
+ :gem => find_executable('gem', 'gem.bat', 'gem1.8'),
48
+ :git => find_executable('git')
49
+ )
50
+
51
+ class <<BoneSplitter
52
+ attr_accessor :libs, :bin
53
+ end
54
+
55
+ private
56
+ def optional_task(name, depends_on_constant)
57
+ # puts "#{name} requires #{depends_on_constant}: #{!!deep_const(depends_on_constant)}"
58
+ if deep_const(depends_on_constant) then
59
+ yield
60
+ else
61
+ task name do
62
+ "You're missing a dependency to run this thread (#{depends_on_constant})"
63
+ end
64
+ end
65
+ end
66
+
67
+ def deep_const(name)
68
+ name.split(/::/).inject(Object) { |nesting, name|
69
+ return nil unless nesting.const_defined?(name)
70
+ nesting.const_get(name)
71
+ }
72
+ end
73
+
74
+ def version_proc(constant)
75
+ proc {
76
+ file = constant.gsub(/::/, '/').downcase
77
+ require(file)
78
+ version = deep_const(constant)
79
+ version && version.to_s
80
+ }
81
+ end
82
+
83
+ def quietly
84
+ verbose, $VERBOSE = $VERBOSE, nil
85
+ yield
86
+ ensure
87
+ $VERBOSE = verbose
88
+ end
89
+
90
+ def silenced
91
+ a,b = $stderr, $stdout
92
+ $stderr = StringIO.new
93
+ $stdout = StringIO.new
94
+ yield
95
+ ensure
96
+ $stderr, $stdout = a,b
97
+ end
98
+
99
+ # same as lib? but aborts if a dependency isn't met
100
+ def dependency(names, warn_message=nil)
101
+ abort unless lib?(names, warn_message)
102
+ end
103
+ alias dependencies dependency
104
+
105
+ def lib?(names, warn_message=nil)
106
+ Array(names).map { |name|
107
+ next true if BoneSplitter.libs[name] # already been required earlier
108
+ begin
109
+ silenced do
110
+ require name
111
+ end
112
+ BoneSplitter.libs[name] = true
113
+ true
114
+ rescue LoadError
115
+ warn(warn_message % name) if warn_message
116
+ false
117
+ end
118
+ }.all? # map first so we get all messages at once
119
+ end
120
+
121
+ # Add a lib as present. Use this to fake existence of a lib if you have
122
+ # an in-place substitute for it, like e.g. RDiscount for Markdown.
123
+ def has_lib!(*names)
124
+ names.each { |name|
125
+ BoneSplitter.libs[name] = true
126
+ }
127
+ end
128
+
129
+ def manifest(mani=Project.meta.manifest)
130
+ if File.exist?(mani) then
131
+ File.read(mani).split(/\n/)
132
+ else
133
+ []
134
+ end
135
+ end
136
+
137
+ def bin
138
+ BoneSplitter.bin
139
+ end
140
+
141
+ def manifest_candidates
142
+ cands = Array(Project.manifest.include || '**/*').inject([]) { |a,e| a+Dir[e] }
143
+
144
+ # remove all that are to exclude
145
+ if Project.manifest.exclude then
146
+ Project.manifest.exclude.map { |glob| cands -= Dir[glob] }
147
+ end
148
+ # remove all directories
149
+ cands - Dir['**/*/'].map { |e| e.chop }
150
+ end
151
+
152
+ def has_version?(having_version, minimal_version, maximal_version=nil)
153
+ a = having_version.split(/\./).map { |e| e.to_i }
154
+ b = minimal_version.split(/\./).map { |e| e.to_i }
155
+ c = maximal_version && maximal_version.split(/\./).map { |e| e.to_i }
156
+ c ? a.between?(b,c) : a >= b
157
+ end
158
+
159
+ # requires that 'readme' is a file in markdown format and that Markdown exists
160
+ def extract_summary(file=Project.meta.readme)
161
+ return nil unless File.readable?(file)
162
+ case File.extname(file)
163
+ when '.rdoc'
164
+ File.read('README.rdoc')[/^(\s*=+)\s+SUMMARY\b.*?\n(.*?)\n\1/m, 2]
165
+ when '.markdown'
166
+ return nil unless lib?(%w'hpricot markdown', "Requires %s to extract the summary")
167
+ html = Markdown.new(File.read(file)).to_html
168
+ (Hpricot(html)/"h2[text()=Summary]").first.next_sibling.inner_text.strip
169
+ end
170
+ rescue => e
171
+ warn "Failed extracting the summary: #{e}"
172
+ nil
173
+ end
174
+
175
+ # requires that 'readme' is a file in markdown format and that Markdown exists
176
+ def extract_description(file=Project.meta.readme)
177
+ return nil unless File.readable?(file)
178
+ case File.extname(file)
179
+ when '.rdoc'
180
+ File.read('README.rdoc')[/^(\s*=+)\s+DESCRIPTION\b.*?\n(.*?)\n\1/m, 2]
181
+ when '.markdown'
182
+ return nil unless lib?('hpricot markdown', "Requires %s to extract the summary")
183
+ html = Markdown.new(File.read(file)).to_html
184
+ (Hpricot(html)/"h2[text()=Description]").first.next_sibling.inner_text.strip
185
+ end
186
+ rescue => e
187
+ warn "Failed extracting the description: #{e}"
188
+ nil
189
+ end
190
+
191
+ # Create a Gem::Specification from Project.gem data.
192
+ def gem_spec(from)
193
+ Gem::Specification.new do |s|
194
+ s.name = from.name
195
+ s.version = from.version
196
+ s.summary = from.summary
197
+ s.authors = from.authors
198
+ s.email = from.email
199
+ s.homepage = from.homepage
200
+ s.rubyforge_project = from.rubyforge_project
201
+ s.description = from.description
202
+ s.required_ruby_version = from.required_ruby_version if from.required_ruby_version
203
+
204
+ from.dependencies.each do |dep|
205
+ s.add_dependency(*dep)
206
+ end if from.dependencies
207
+
208
+ s.files = from.files
209
+ s.executables = from.executables.map {|fn| File.basename(fn)}
210
+ s.extensions = from.extensions
211
+
212
+ s.bindir = from.bin_dir
213
+ s.require_paths = from.require_paths if from.require_paths
214
+
215
+ s.rdoc_options = from.rdoc_options
216
+ s.extra_rdoc_files = from.extra_rdoc_files
217
+ s.has_rdoc = from.has_rdoc
218
+
219
+ if from.test_file then
220
+ s.test_file = from.test_file
221
+ elsif from.test_files
222
+ s.test_files = from.test_files
223
+ end
224
+
225
+ # Do any extra stuff the user wants
226
+ from.extras.each do |msg, val|
227
+ case val
228
+ when Proc
229
+ val.call(s.send(msg))
230
+ else
231
+ s.send "#{msg}=", val
232
+ end
233
+ end
234
+ end # Gem::Specification.new
235
+ end
236
+
237
+ # Returns a good name for the gem-file using the spec and the package-name.
238
+ def gem_file(spec, package_name)
239
+ if spec.platform == Gem::Platform::RUBY then
240
+ "#{package_name}.gem"
241
+ else
242
+ "#{package_name}-#{spec.platform}.gem"
243
+ end
244
+ end
245
+ end # BoneSplitter
@@ -0,0 +1,69 @@
1
+ #--
2
+ # Copyright 2007-2008 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ # fix pre-rubygems 1.3 nuisance
10
+ begin
11
+ require 'rubygems'
12
+ module Kernel
13
+ private :gem
14
+ private :require
15
+ private :open
16
+ end
17
+ rescue LoadError; end
18
+
19
+ # FIXME: add a method_added hook to Object and Kernel to keep ProjectClass clean.
20
+
21
+ # This class is not written for long running scripts as it leaks symbols.
22
+ # It is openstructlike, but a bit more lightweight and blankslate so any method will work
23
+ # You can set values to procs and call __finalize__ to get them replaced by the value
24
+ # returned by the proc.
25
+ class ProjectClass
26
+ names = public_instance_methods - %w[initialize inspect __id__ __send__]
27
+ names.each { |m| undef_method m }
28
+
29
+ attr_reader :__hash__
30
+
31
+ def initialize(values=nil)
32
+ @__hash__ = values || {}
33
+ end
34
+
35
+ def [](key)
36
+ @__hash__[key.to_sym]
37
+ end
38
+
39
+ def []=(key,value)
40
+ @__hash__[key.to_sym] = value
41
+ end
42
+
43
+ # All values that respond to .call are replaced by the value
44
+ # returned when calling.
45
+ def __finalize__
46
+ @__hash__.each { |k,v|
47
+ @__hash__[k] = v.call if v.respond_to?(:call)
48
+ }
49
+ end
50
+
51
+ def method_missing(name, *args)
52
+ case args.length
53
+ when 0
54
+ if key = name.to_s[/^(.*)\?$/, 1] then
55
+ !!@__hash__[key.to_sym]
56
+ else
57
+ @__hash__[name]
58
+ end
59
+ when 1
60
+ if key = name.to_s[/^(.*)=$/, 1] then
61
+ @__hash__[key.to_sym] = args.first
62
+ else
63
+ super
64
+ end
65
+ else
66
+ super
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,24 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ namespace :copyright do
10
+ task :update do
11
+ manifest().each { |file|
12
+ data = File.read(file).gsub(/(copyright \d+)(?:(\s*-\s*)\d+)?( by)/i) {
13
+ copyright = "#{$1}#{$2 || '-'}#{Time.now.year}#{$3}"
14
+ puts "#{file}: replacing #{$&.inspect} with #{copyright.inspect}"
15
+ copyright
16
+ }
17
+ File.open(file, "wb") { |fh| fh.write(data) }
18
+ }
19
+ end
20
+ end # namespace :copyright
21
+
22
+ desc 'Alias to copyright:update'
23
+ task :copyright => 'copyright:update'
24
+
@@ -0,0 +1,119 @@
1
+ #--
2
+ # Copyright 2007-2008 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ namespace :gem do
10
+
11
+ # No data in Project
12
+ if Project.gem.nil? then
13
+ task :missing_project do
14
+ abort("No instructions in Project to run the gem tasks")
15
+ end
16
+
17
+ task :package => :missing_project
18
+ task :info => :missing_project
19
+ task :install => :missing_project
20
+ task :uninstall => :missing_project
21
+ task :cleanup => :missing_project
22
+ task :clobber
23
+
24
+ # Rubygems is not installed
25
+ elsif !lib?('rubygems') then
26
+ task :missing_rubygems do
27
+ abort("Requires rubygems to run")
28
+ end
29
+
30
+ task :package => :missing_rubygems
31
+ task :info => :missing_rubygems
32
+ task :install => :missing_rubygems
33
+ task :uninstall => :missing_rubygems
34
+ task :cleanup => :missing_rubygems
35
+ task :clobber
36
+
37
+ # Prerequisites met
38
+ else
39
+ Project.gem.name ||= Project.meta.name
40
+ Project.gem.version ||= Project.meta.version
41
+ Project.gem.summary ||= Project.meta.summary
42
+ Project.gem.description ||= Project.meta.description
43
+ Project.gem.authors ||= Project.meta.authors || Array(Project.meta.author)
44
+ Project.gem.email ||= Project.meta.email
45
+ Project.gem.homepage ||= Project.meta.website
46
+ Project.gem.rubyforge_project ||= (Project.rubyforge && Project.rubyforge.name) || Project.meta.name
47
+ Project.gem.files ||= manifest()
48
+ Project.gem.executables ||= Array(Project.gem.executable)
49
+ Project.gem.extensions ||= Project.gem.files.grep %r/extconf\.rb$/
50
+ Project.gem.bin_dir ||= "bin"
51
+
52
+ Project.gem.rdoc_options ||= Project.rdoc && Project.rdoc.options
53
+ Project.gem.extra_rdoc_files ||= Project.rdoc && Project.rdoc.extra_files
54
+ Project.gem.rdoc_options ||= Project.rdoc && Project.rdoc.options
55
+ Project.gem.__finalize__
56
+ Project.gem.spec = gem_spec(Project.gem)
57
+
58
+ # task gem:package
59
+ dependency 'rake/gempackagetask', 'Requires rake/gempackagetask'
60
+ pkg = Rake::GemPackageTask.new(Project.gem.spec) do |pkg|
61
+ pkg.need_tar = Project.gem.need_tar
62
+ pkg.need_zip = Project.gem.need_zip
63
+ pkg.package_files = Project.gem.files if Project.gem.files
64
+ end
65
+ # Rake::Task['gem:package'].instance_variable_set(:@full_comment, nil)
66
+
67
+ Project.gem.gem_file ||= gem_file(Project.gem.spec, pkg.package_name)
68
+
69
+ desc 'Show information about the gem'
70
+ task :info do
71
+ puts "package_files:"
72
+ puts Project.gem.files
73
+ puts Project.gem.spec.to_ruby
74
+ end
75
+
76
+ desc "Build the gem file #{Project.gem.gem_file}"
77
+ task :package => %W[#{pkg.package_dir}/#{Project.gem.gem_file}]
78
+
79
+ file "#{pkg.package_dir}/#{Project.gem.gem_file}" => [pkg.package_dir, *Project.gem.files] do
80
+ when_writing("Creating GEM") {
81
+ Gem::Builder.new(Project.gem.spec).build
82
+ verbose(true) {
83
+ mv Project.gem.gem_file, "#{pkg.package_dir}/#{Project.gem.gem_file}"
84
+ }
85
+ }
86
+ end
87
+
88
+ desc 'Install the gem'
89
+ task :install => [:clobber, 'gem:package'] do
90
+ sh "#{bin.sudo unless File.writable?(Gem.dir)} #{bin.gem} install --no-update-sources pkg/#{Project.gem.spec.full_name}"
91
+ end
92
+
93
+ desc 'Reinstall the gem'
94
+ task :reinstall => [:uninstall, :install]
95
+
96
+ desc 'Uninstall the gem'
97
+ task :uninstall do
98
+ if installed_list = Gem.source_index.find_name(Project.gem.name) then
99
+ installed_versions = installed_list.map { |s| s.version.to_s }
100
+ if installed_versions.include?(Project.gem.version) then
101
+ sh "#{bin.sudo unless File.writable?(Gem.dir)} #{bin.gem} uninstall --version '#{Project.gem.version}' --ignore-dependencies --executables #{Project.gem.name}"
102
+ end
103
+ end
104
+ end
105
+
106
+ desc 'Cleanup the gem'
107
+ task :cleanup do
108
+ abort("Gem name not set in Project.gem") unless Project.gem.name
109
+ sh "#{bin.sudo unless File.writable?(Gem.dir)} #{bin.gem} cleanup #{Project.gem.name}"
110
+ end
111
+
112
+ task :clobber => :clobber_package
113
+ end
114
+ end # namespace :gem
115
+
116
+ desc 'Alias to gem:package'
117
+ task :gem => 'gem:package'
118
+ task :clobber => 'gem:clobber'
119
+