numerouno 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 0.0.1 2009-05-07
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
5
+ * mmmm...has that new gem smell
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/numerouno.rb
6
+ lib/numerouno-parsing.rb
7
+ lib/numerouno/combiner.rb
8
+ lib/numerouno/parser.rb
9
+ lib/numerouno/search.rb
10
+ script/console
11
+ script/destroy
12
+ script/generate
13
+ tasks/rspec.rake
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = Numerouno
2
+
3
+ * http://github.com/brentsnook/numerouno
4
+
5
+ English natural language parser for numbers.
6
+
7
+ * Parse 'five' to return 5
8
+ * Parse 'seven hundred and fifty two billion, four hundred and twenty million, sixty thousand and forty two' to return 752,420,060,042
9
+ * Parse 'siebenundzwanzig' to have it fail because it doesn't recognise German.
10
+
11
+ Recognises numbers in the trillions.
12
+
13
+ == Installation
14
+
15
+ Whoah, hang on there. Not up on Rubyforge yet but hopefully soon. When it is:
16
+
17
+ sudo gem install numerouno
18
+
19
+ === Building the Gem yourself
20
+
21
+ Grab the code from github:
22
+
23
+ git clone git://github.com/brentsnook/numerouno.git
24
+ cd numerouno
25
+ rake install_gem
26
+
27
+ == Use
28
+
29
+ Just require numerouno to add magical number parsing powers to your strings:
30
+
31
+ require 'numerouno'
32
+ 'sixty five'.as_number
33
+
34
+ Or if you're a sook who doesn't like the idea of String being opened up:
35
+
36
+ require 'numerouno-parsing'
37
+ Numerouno.parse 'sixty five'
38
+
39
+ == How does it all work?
40
+
41
+ The English language has explicit rules for expressing numbers. Numeruno attempts to recognise strings based on these rules.
42
+
43
+ Check out http://wiki.github.com/brentsnook/numerouno for details.
44
+
45
+ == What is it good for?
46
+
47
+ The main serving suggestion is to toss it with Chronic[http://chronic.rubyforge.org/] and Cucumber[http://cukes.info/] for an even tastier BDD salad.
48
+
49
+ == License
50
+
51
+ (The MIT License)
52
+
53
+ Copyright (c) 2009 Brent Snook http://fuglylogic.com
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ 'Software'), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
69
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
70
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
71
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
72
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/numerouno'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('numerouno', Numerouno::VERSION) do |p|
7
+ p.developer 'Brent Snook', 'brent@fuglylogic.com'
8
+ p.summary = %q{English natural language parser for numbers.}
9
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
10
+ p.rubyforge_name = p.name
11
+ p.extra_dev_deps = [
12
+ ['newgem', ">= #{::Newgem::VERSION}"],
13
+ ['rspec', '>= 1.2.4'],
14
+ ['cucumber', '>= 0.3.1']
15
+ ]
16
+
17
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
18
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
19
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
20
+ p.rsync_args = '-av --delete --ignore-errors'
21
+ end
22
+
23
+ require 'newgem/tasks' # load /tasks/*.rake
24
+ Dir['tasks/**/*.rake'].each { |t| load t }
25
+
26
+ task :default => [:spec, :features]
@@ -0,0 +1,65 @@
1
+ module Numerouno
2
+
3
+ module CombinerMethods
4
+
5
+ def combine numbers
6
+ Combiner.new numbers
7
+ end
8
+
9
+ end
10
+
11
+ class Combiner
12
+
13
+ def of_power power
14
+ @power = power
15
+ self
16
+ end
17
+
18
+ def apply!
19
+ @numbers.each_with_index do |number, index|
20
+ @current = index
21
+ if number_is_correct_power?
22
+ apply :*, to_left if should_multiply?
23
+ apply :+, to_right if should_add?
24
+ end
25
+ end
26
+
27
+ @numbers.compact!
28
+ end
29
+
30
+ private
31
+
32
+ def initialize numbers
33
+ @numbers = numbers
34
+ end
35
+
36
+ def should_multiply?
37
+ @current > 0 and @power > 10
38
+ end
39
+
40
+ def should_add?
41
+ @current < (@numbers.length - 1) and number > @numbers[to_right]
42
+ end
43
+
44
+ def apply operation, index
45
+ @numbers[@current] = number.send operation, @numbers[index]
46
+ @numbers[index] = nil
47
+ end
48
+
49
+ def to_left
50
+ @current - 1
51
+ end
52
+
53
+ def to_right
54
+ @current + 1
55
+ end
56
+
57
+ def number_is_correct_power?
58
+ number and (number % @power == 0) and number < (@power * 10)
59
+ end
60
+
61
+ def number
62
+ @numbers[@current]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ module Numerouno
2
+ module Parser
3
+
4
+ extend CombinerMethods
5
+ extend SearchMethods
6
+
7
+ def self.number_from string
8
+ numbers = numbers_within string
9
+ numbers.empty? ? raise(NoNumberFoundError, "No number found in string: #{string}") :
10
+ total(numbers)
11
+ end
12
+
13
+ private
14
+
15
+ def self.total numbers
16
+ [10, 100, 1000, 1000000, 1000000000, 1000000000000].each do |power|
17
+ combine(numbers).of_power(power).apply!
18
+ end
19
+ numbers.inject(0){|sum, add| sum + add}
20
+ end
21
+
22
+ end
23
+
24
+ class NoNumberFoundError < StandardError; end
25
+ end
@@ -0,0 +1,94 @@
1
+ module Numerouno
2
+
3
+ module SearchMethods
4
+
5
+ def numbers_within string
6
+ Search.new(string).find_all
7
+ end
8
+
9
+ end
10
+
11
+ class Search
12
+
13
+ # the mapping between number strings and numbers needs to be ordered
14
+ # this is to avoid the wrong mapping being picked up
15
+ # i.e /seven/ would match 'seventy' before /seventy/
16
+ NUMBER_STRINGS = [
17
+ ['sixty', 60],
18
+ ['seventy', 70],
19
+ ['eighty', 80],
20
+ ['ninety', 90],
21
+ ['fourteen', 14],
22
+ ['sixteen', 16],
23
+ ['seventeen', 17],
24
+ ['eighteen', 18],
25
+ ['nineteen', 19],
26
+
27
+ ['zero', 0],
28
+ ['one', 1],
29
+ ['two', 2],
30
+ ['three', 3],
31
+ ['four', 4],
32
+ ['five', 5],
33
+ ['six', 6],
34
+ ['seven', 7],
35
+ ['eight', 8],
36
+ ['nine', 9],
37
+ ['ten', 10],
38
+ ['eleven', 11],
39
+ ['twelve', 12],
40
+ ['thirteen', 13],
41
+ ['fifteen', 15],
42
+ ['twenty', 20],
43
+ ['thirty', 30],
44
+ ['forty', 40],
45
+ ['fifty', 50],
46
+
47
+ ['hundred', 100],
48
+ ['thousand', 1000],
49
+ ['million', 1000000],
50
+ ['billion', 1000000000],
51
+ ['trillion', 1000000000000]
52
+ ]
53
+
54
+ NUMBER_LOOKUP = NUMBER_STRINGS.inject(Hash.new) do |hash, map|
55
+ hash[map[0]] = map[1]
56
+ hash
57
+ end
58
+
59
+ def initialize string
60
+ @string = string
61
+ @numbers = []
62
+ end
63
+
64
+ def find_all
65
+ search until string_exhausted?
66
+ @numbers.compact
67
+ end
68
+
69
+ private
70
+
71
+ def search
72
+ if match = next_match
73
+ @string = string_without match
74
+ @numbers[match.pre_match.length] = NUMBER_LOOKUP[match.to_s]
75
+ else
76
+ @string = ''
77
+ end
78
+ end
79
+
80
+ def string_without match
81
+ match.pre_match + (' ' * match.to_s.length) + match.post_match
82
+ end
83
+
84
+ def next_match
85
+ NUMBER_STRINGS.collect do |number_string, number|
86
+ @string.match number_string
87
+ end.compact.first
88
+ end
89
+
90
+ def string_exhausted?
91
+ @string.sub(' ', '').empty?
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ [
5
+ 'combiner',
6
+ 'search',
7
+ 'parser'
8
+ ].each {|file| require "numerouno/#{file}"}
9
+
10
+ module Numerouno
11
+ VERSION = '0.0.1'
12
+
13
+ def self.parse string
14
+ Parser.number_from string
15
+ end
16
+ end
data/lib/numerouno.rb ADDED
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), 'numerouno-parsing')
2
+
3
+ module Numerouno
4
+
5
+ module StringExtensions
6
+
7
+ def as_number
8
+ Numerouno.parse self
9
+ end
10
+ end
11
+
12
+ end
13
+
14
+ String.send :include, Numerouno::StringExtensions
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/numerouno.rb'}"
9
+ puts "Loading numerouno gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: numerouno
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brent Snook
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-09 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.4
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: cucumber
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.3.1
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: hoe
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.8.0
54
+ version:
55
+ description: ""
56
+ email:
57
+ - brent@fuglylogic.com
58
+ executables: []
59
+
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - History.txt
64
+ - Manifest.txt
65
+ - README.rdoc
66
+ files:
67
+ - History.txt
68
+ - Manifest.txt
69
+ - README.rdoc
70
+ - Rakefile
71
+ - lib/numerouno.rb
72
+ - lib/numerouno-parsing.rb
73
+ - lib/numerouno/combiner.rb
74
+ - lib/numerouno/parser.rb
75
+ - lib/numerouno/search.rb
76
+ - script/console
77
+ - script/destroy
78
+ - script/generate
79
+ - tasks/rspec.rake
80
+ has_rdoc: true
81
+ homepage: http://github.com/brentsnook/numerouno
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --main
85
+ - README.rdoc
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: "0"
93
+ version:
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: "0"
99
+ version:
100
+ requirements: []
101
+
102
+ rubyforge_project: numerouno
103
+ rubygems_version: 1.3.1
104
+ signing_key:
105
+ specification_version: 2
106
+ summary: English natural language parser for numbers.
107
+ test_files: []
108
+