tickle 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/.rvmrc ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # .rvmrc file for tdt application
4
+
5
+ if [[ "Darwin" = "$(uname)" ]] ; then
6
+ rvm ruby-1.9.1@tickle --symlink textmate
7
+ else
8
+ rvm ruby-1.9.1@tickle
9
+ fi
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Joshua Lippiner
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,65 @@
1
+ = tickle
2
+ http://github.com/noctivityinc/tickle
3
+ by Joshua Lippiner, Noctivity
4
+
5
+ -- DESCRIPTION
6
+
7
+ Tickle is a natural language parser for recurring events.
8
+
9
+ Tickle is designed to be a compliment of Chronic and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc."
10
+
11
+ Tickle has one main method, "Tickle.parse," which returns two variables, the next interval followed by the interval length in days. Tickle returns nil if it cannot parse the string cannot be parsed.
12
+
13
+ -- INSTALLATION
14
+
15
+ Tickle can be installed via RubyGems:
16
+
17
+ $ gem install tickle
18
+
19
+ -- TINKERING
20
+
21
+ Everything's at Github - http://github.com/noctivityinc/tickle
22
+
23
+ == USAGE
24
+
25
+ You can parse strings containing a natural language interval using the Tickle.parse method.
26
+
27
+ require 'rubygems'
28
+ require 'tickle'
29
+
30
+ Time.now #=> 2010-04-21 14:32:02 -0400
31
+
32
+ Tickle.parse('every 2 days')
33
+ #=> 2010-04-23, 2
34
+
35
+ Tickle.parse('every Sunday') #=> note, this upcoming Sunday is 4/25/2010
36
+ #=> 2010-04-25, 7
37
+
38
+ Tickle.parse('every 3 weeks')
39
+ #=> 2010-05-12, 21
40
+
41
+ Tickle.parse('2 days')
42
+ #=> 2010-04-23, 2
43
+
44
+
45
+ You can either pass a string prefixed with the word "every" or simply the time frame.
46
+
47
+ -- LIMITATIONS
48
+
49
+ Currently, Tickle only works for day intervals but feel free to fork and add time-based interval support. Also, numbers must be entered in numeric and not string form (i.e. 3 not three).
50
+
51
+
52
+
53
+ == Note on Patches/Pull Requests
54
+
55
+ * Fork the project.
56
+ * Make your feature addition or bug fix.
57
+ * Add tests for it. This is important so I don't break it in a
58
+ future version unintentionally.
59
+ * Commit, do not mess with rakefile, version, or history.
60
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
61
+ * Send me a pull request. Bonus points for topic branches.
62
+
63
+ == Copyright
64
+
65
+ Copyright (c) 2010 Joshua Lippiner. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "tickle"
8
+ gem.summary = 'natural language parser for recurring events'
9
+ gem.description = 'Tickle is a date/time helper gem to help parse natural language into a recurring pattern. Tickle is designed to be a compliment of Chronic and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc.'
10
+ gem.email = "jlippiner@noctivity.com"
11
+ gem.homepage = "http://github.com/noctivityinc/tickle"
12
+ gem.authors = ["Joshua Lippiner"]
13
+ gem.add_dependency('chronic', '>= 0.2.3')
14
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
15
+
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/test_*.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/test_*.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ task :test => :check_dependencies
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "tickle #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,103 @@
1
+ require 'strscan'
2
+
3
+ class Numerizer
4
+
5
+ DIRECT_NUMS = [
6
+ ['eleven', '11'],
7
+ ['twelve', '12'],
8
+ ['thirteen', '13'],
9
+ ['fourteen', '14'],
10
+ ['fifteen', '15'],
11
+ ['sixteen', '16'],
12
+ ['seventeen', '17'],
13
+ ['eighteen', '18'],
14
+ ['nineteen', '19'],
15
+ ['ninteen', '19'], # Common mis-spelling
16
+ ['zero', '0'],
17
+ ['one', '1'],
18
+ ['two', '2'],
19
+ ['three', '3'],
20
+ ['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
21
+ ['five', '5'],
22
+ ['six(\W|$)', '6\1'],
23
+ ['seven(\W|$)', '7\1'],
24
+ ['eight(\W|$)', '8\1'],
25
+ ['nine(\W|$)', '9\1'],
26
+ ['ten', '10'],
27
+ ['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
28
+ ]
29
+
30
+ TEN_PREFIXES = [ ['twenty', 20],
31
+ ['thirty', 30],
32
+ ['fourty', 40],
33
+ ['fifty', 50],
34
+ ['sixty', 60],
35
+ ['seventy', 70],
36
+ ['eighty', 80],
37
+ ['ninety', 90]
38
+ ]
39
+
40
+ BIG_PREFIXES = [ ['hundred', 100],
41
+ ['thousand', 1000],
42
+ ['million', 1_000_000],
43
+ ['billion', 1_000_000_000],
44
+ ['trillion', 1_000_000_000_000],
45
+ ]
46
+
47
+ class << self
48
+ def numerize(string)
49
+ string = string.dup
50
+
51
+ # preprocess
52
+ string.gsub!(/ +|([^\d])-([^d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
53
+ string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
54
+
55
+ # easy/direct replacements
56
+
57
+ DIRECT_NUMS.each do |dn|
58
+ string.gsub!(/#{dn[0]}/i, dn[1])
59
+ end
60
+
61
+ # ten, twenty, etc.
62
+
63
+ TEN_PREFIXES.each do |tp|
64
+ string.gsub!(/(?:#{tp[0]})( *\d(?=[^\d]|$))*/i) { (tp[1] + $1.to_i).to_s }
65
+ end
66
+
67
+ # hundreds, thousands, millions, etc.
68
+
69
+ BIG_PREFIXES.each do |bp|
70
+ string.gsub!(/(\d*) *#{bp[0]}/i) { (bp[1] * $1.to_i).to_s}
71
+ andition(string)
72
+ #combine_numbers(string) # Should to be more efficient way to do this
73
+ end
74
+
75
+ # fractional addition
76
+ # I'm not combining this with the previous block as using float addition complicates the strings
77
+ # (with extraneous .0's and such )
78
+ string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
79
+
80
+ string
81
+ end
82
+
83
+ private
84
+ def andition(string)
85
+ sc = StringScanner.new(string)
86
+ while(sc.scan_until(/(\d+)( | and )(\d+)(?=[^\w]|$)/i))
87
+ if sc[2] =~ /and/ || sc[1].size > sc[3].size
88
+ string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[3].to_i).to_s
89
+ sc.reset
90
+ end
91
+ end
92
+ end
93
+
94
+ # def combine_numbers(string)
95
+ # sc = StringScanner.new(string)
96
+ # while(sc.scan_until(/(\d+)(?: | and |-)(\d+)(?=[^\w]|$)/i))
97
+ # string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[2].to_i).to_s
98
+ # sc.reset
99
+ # end
100
+ # end
101
+
102
+ end
103
+ end
@@ -0,0 +1,25 @@
1
+ module Tickle
2
+ class << self
3
+
4
+ def parse(text, specified_options = {})
5
+ # get options and set defaults if necessary
6
+ default_options = {:now => Time.now}
7
+ options = default_options.merge specified_options
8
+
9
+ # ensure the specified options are valid
10
+ specified_options.keys.each do |key|
11
+ default_options.keys.include?(key) || raise(InvalidArgumentException, "#{key} is not a valid option key.")
12
+ end
13
+ Chronic.parse(options[:now]) || rails(InvalidArgumentException, ':now specified is not a valid datetime.')
14
+
15
+ # store now for later =)
16
+ @now = options[:now]
17
+
18
+ # put the text into a normal format to ease scanning using Chronic
19
+ text = Chronic.pre_normalize(text)
20
+
21
+ return text
22
+ end
23
+
24
+ end
25
+ end
data/lib/tickle.rb ADDED
@@ -0,0 +1,20 @@
1
+ #=============================================================================
2
+ #
3
+ # Name: Tickle
4
+ # Author: Joshua Lippiner
5
+ # Purpose: Parse natural language into recuring intervals
6
+ #
7
+ #=============================================================================
8
+
9
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
10
+
11
+ require 'chronic'
12
+ require 'numerizer/numerizer'
13
+
14
+ require 'tickle/tickle'
15
+
16
+ module Tickle
17
+ VERSION = "0.0.1"
18
+
19
+ def self.debug; false; end
20
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'tickle'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestTickle < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tickle
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Joshua Lippiner
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-21 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: chronic
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 3
31
+ version: 0.2.3
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: thoughtbot-shoulda
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: Tickle is a date/time helper gem to help parse natural language into a recurring pattern. Tickle is designed to be a compliment of Chronic and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc.
47
+ email: jlippiner@noctivity.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.rdoc
55
+ files:
56
+ - .document
57
+ - .gitignore
58
+ - .rvmrc
59
+ - LICENSE
60
+ - README.rdoc
61
+ - Rakefile
62
+ - VERSION
63
+ - lib/numerizer/numerizer.rb
64
+ - lib/tickle.rb
65
+ - lib/tickle/tickle.rb
66
+ - test/helper.rb
67
+ - test/test_tickle.rb
68
+ has_rdoc: true
69
+ homepage: http://github.com/noctivityinc/tickle
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options:
74
+ - --charset=UTF-8
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.6
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: natural language parser for recurring events
98
+ test_files:
99
+ - test/helper.rb
100
+ - test/test_tickle.rb