dump-parser 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +44 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/dump-parser.gemspec +79 -0
- data/lib/dump-parser.rb +142 -0
- data/spec/integration/dump-parser_spec.rb +49 -0
- data/spec/quality/dump-parser_spec.rb +7 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/unit/dump_parser/class_methods/execute_spec.rb +16 -0
- data/spec/unit/dump_parser/class_methods/has_parser_spec.rb +24 -0
- data/spec/unit/dump_parser/class_methods/lookup_spec.rb +29 -0
- data/spec/unit/dump_parser/class_methods/names_spec.rb +35 -0
- data/spec/unit/dump_parser/class_methods/new_spec.rb +37 -0
- data/spec/unit/dump_parser/class_methods/register_spec.rb +54 -0
- data/spec/unit/dump_parser/class_methods/reset_spec.rb +15 -0
- data/spec/unit/dump_parser/execute_spec.rb +110 -0
- data/spec/unit/dump_parser_spec.rb +4 -0
- metadata +153 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.6.4)
|
7
|
+
bundler (~> 1.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.9.2)
|
11
|
+
rcov (0.9.9)
|
12
|
+
reek (1.2.8)
|
13
|
+
ruby2ruby (~> 1.2)
|
14
|
+
ruby_parser (~> 2.0)
|
15
|
+
sexp_processor (~> 3.0)
|
16
|
+
roodi (2.1.0)
|
17
|
+
ruby_parser
|
18
|
+
rspec (2.3.0)
|
19
|
+
rspec-core (~> 2.3.0)
|
20
|
+
rspec-expectations (~> 2.3.0)
|
21
|
+
rspec-mocks (~> 2.3.0)
|
22
|
+
rspec-core (2.3.1)
|
23
|
+
rspec-expectations (2.3.0)
|
24
|
+
diff-lcs (~> 1.1.2)
|
25
|
+
rspec-mocks (2.3.0)
|
26
|
+
ruby2ruby (1.2.5)
|
27
|
+
ruby_parser (~> 2.0)
|
28
|
+
sexp_processor (~> 3.0)
|
29
|
+
ruby_parser (2.0.6)
|
30
|
+
sexp_processor (~> 3.0)
|
31
|
+
sexp_processor (3.0.5)
|
32
|
+
yard (0.7.2)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
bundler (~> 1.0)
|
39
|
+
jeweler (~> 1.6)
|
40
|
+
rcov
|
41
|
+
reek (~> 1.2)
|
42
|
+
roodi (~> 2.1)
|
43
|
+
rspec (~> 2)
|
44
|
+
yard (~> 0.7)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Markus Schirp
|
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,50 @@
|
|
1
|
+
= dump-parser
|
2
|
+
|
3
|
+
I found my self doing this serveral times:
|
4
|
+
|
5
|
+
* Start a project where I have to import data from legacy (CSV) formats
|
6
|
+
* Need to parse strings into various formats (Date,Time,Integer,Symbols,Domain-Specific)
|
7
|
+
* There are many (more than 40) string based conversion formats per project
|
8
|
+
* Maintaining this domain knowlege consistent and error free over project livetime
|
9
|
+
* Really hate to maintain "a dsl free big clumb of sequencial and self repeating code"
|
10
|
+
|
11
|
+
Goal of this gem is to provide a clean DSL to parse strings (CSV fields) into usable objects.
|
12
|
+
|
13
|
+
== Example
|
14
|
+
|
15
|
+
require 'dump-parser'
|
16
|
+
|
17
|
+
DumpParser.register :dd_mm_yyyy_date_time do
|
18
|
+
nil_if_empty
|
19
|
+
require_format %r(\A(\d{2})\.(\d{2})\.(\d{4})\Z)
|
20
|
+
begin
|
21
|
+
DateTime.new(match[3].to_i,match[2].to_i,match[1].to_i)
|
22
|
+
rescue ArgumentError
|
23
|
+
error 'is invalid date'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
DumpParser.register :required_integer do
|
28
|
+
require_format %r(\A\d+\Z)
|
29
|
+
value.to_i(10)
|
30
|
+
end
|
31
|
+
|
32
|
+
DumpParser.execute :dd_mm_yyyy_date_time, "" # returns nil
|
33
|
+
DumpParser.execute :dd_mm_yyyy_date_time, "10.01.1901" # returns DateTime.new(1901,01,10)
|
34
|
+
DumpParser.execute :dd_mm_yyyy_date_time, "invalid" # raises DumpParser::ParseException.new('dd_mm_yyyy_date: value "invalid" does not match required format')
|
35
|
+
DumpParser.execute :dd_mm_yyyy_date_time, "31.02.2011" # raises DumpParser::ParseException.new('dd_mm_yyyy_date: value "31.02.2011" is invalid date')
|
36
|
+
|
37
|
+
== Contributing to dump-parser
|
38
|
+
|
39
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
40
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
41
|
+
* Fork the project
|
42
|
+
* Start a feature/bugfix branch
|
43
|
+
* Commit and push until you are happy with your contribution
|
44
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
45
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
46
|
+
|
47
|
+
== Copyright
|
48
|
+
|
49
|
+
Copyright (c) 2011 Markus Schirp. See LICENSE.txt for
|
50
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "dump-parser"
|
18
|
+
gem.homepage = "http://github.com/mbj/dump-parser"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Simple string2value DSL}
|
21
|
+
gem.description = %Q{Provides an easy way to manage a huge amount of domain specific string2value conversions. Mostly useful to convert legacy CSV-Fields from strings with domain specific rules}
|
22
|
+
gem.email = "mbj@seonic.net"
|
23
|
+
gem.authors = ["Markus Schirp"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'reek/rake/task'
|
40
|
+
Reek::Rake::Task.new do |t|
|
41
|
+
t.fail_on_error = true
|
42
|
+
t.verbose = false
|
43
|
+
t.source_files = 'lib/**/*.rb'
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'roodi'
|
47
|
+
require 'roodi_task'
|
48
|
+
RoodiTask.new do |t|
|
49
|
+
t.verbose = false
|
50
|
+
end
|
51
|
+
|
52
|
+
task :default => :spec
|
53
|
+
|
54
|
+
require 'yard'
|
55
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/dump-parser.gemspec
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{dump-parser}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Markus Schirp"]
|
12
|
+
s.date = %q{2011-07-18}
|
13
|
+
s.description = %q{Provides an easy way to manage a huge amount of domain specific string2value conversions. Mostly useful to convert legacy CSV-Fields from strings with domain specific rules}
|
14
|
+
s.email = %q{mbj@seonic.net}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"dump-parser.gemspec",
|
29
|
+
"lib/dump-parser.rb",
|
30
|
+
"spec/integration/dump-parser_spec.rb",
|
31
|
+
"spec/quality/dump-parser_spec.rb",
|
32
|
+
"spec/spec_helper.rb",
|
33
|
+
"spec/unit/dump_parser/class_methods/execute_spec.rb",
|
34
|
+
"spec/unit/dump_parser/class_methods/has_parser_spec.rb",
|
35
|
+
"spec/unit/dump_parser/class_methods/lookup_spec.rb",
|
36
|
+
"spec/unit/dump_parser/class_methods/names_spec.rb",
|
37
|
+
"spec/unit/dump_parser/class_methods/new_spec.rb",
|
38
|
+
"spec/unit/dump_parser/class_methods/register_spec.rb",
|
39
|
+
"spec/unit/dump_parser/class_methods/reset_spec.rb",
|
40
|
+
"spec/unit/dump_parser/execute_spec.rb",
|
41
|
+
"spec/unit/dump_parser_spec.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/mbj/dump-parser}
|
44
|
+
s.licenses = ["MIT"]
|
45
|
+
s.require_paths = ["lib"]
|
46
|
+
s.rubygems_version = %q{1.6.2}
|
47
|
+
s.summary = %q{Simple string2value DSL}
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_development_dependency(%q<rspec>, ["~> 2"])
|
54
|
+
s.add_development_dependency(%q<yard>, ["~> 0.7"])
|
55
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
56
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6"])
|
57
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2"])
|
59
|
+
s.add_development_dependency(%q<roodi>, ["~> 2.1"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rspec>, ["~> 2"])
|
62
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6"])
|
65
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
66
|
+
s.add_dependency(%q<reek>, ["~> 1.2"])
|
67
|
+
s.add_dependency(%q<roodi>, ["~> 2.1"])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<rspec>, ["~> 2"])
|
71
|
+
s.add_dependency(%q<yard>, ["~> 0.7"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6"])
|
74
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<reek>, ["~> 1.2"])
|
76
|
+
s.add_dependency(%q<roodi>, ["~> 2.1"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
data/lib/dump-parser.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# Implements a really dump value 2 value parser DSL
|
2
|
+
class DumpParser
|
3
|
+
# Error raised when parser was feed with an invalid value
|
4
|
+
class ParseError < RuntimeError; end
|
5
|
+
|
6
|
+
DEFAULT_MAP_BLOCK = Proc.new { fetch_map }
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
def initialize(name,map=nil,block=nil)
|
11
|
+
unless block || map
|
12
|
+
raise ArgumentError,'need map block or both'
|
13
|
+
end
|
14
|
+
|
15
|
+
block ||= DEFAULT_MAP_BLOCK
|
16
|
+
|
17
|
+
@name,@map,@block = name,map,block
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute(value)
|
21
|
+
unless value.kind_of? String
|
22
|
+
raise '+value+ must be kind of String'
|
23
|
+
end
|
24
|
+
@value = value
|
25
|
+
begin
|
26
|
+
catch :done do
|
27
|
+
@result = instance_eval(&@block)
|
28
|
+
end
|
29
|
+
returning @result do
|
30
|
+
@result = nil
|
31
|
+
end
|
32
|
+
ensure
|
33
|
+
reset!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
attr_reader :value
|
40
|
+
|
41
|
+
protected :value
|
42
|
+
|
43
|
+
def nil_if_empty
|
44
|
+
value = self.value
|
45
|
+
if value.empty?
|
46
|
+
@result = nil
|
47
|
+
throw :done
|
48
|
+
else
|
49
|
+
value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_if_empty
|
54
|
+
value = self.value
|
55
|
+
if value.empty?
|
56
|
+
parse_error 'must not be empty'
|
57
|
+
else
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def require_format(format)
|
63
|
+
value = self.value
|
64
|
+
@last_match = format.match value
|
65
|
+
if @last_match
|
66
|
+
value
|
67
|
+
else
|
68
|
+
parse_error 'does not match required format'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def match
|
73
|
+
@last_match || raise(RuntimeError,'no current match available')
|
74
|
+
end
|
75
|
+
|
76
|
+
def reset!
|
77
|
+
@value = @result = @match = nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def map
|
81
|
+
@map || raise(RuntimeError,'this parser does not have a map')
|
82
|
+
end
|
83
|
+
|
84
|
+
def returning(value)
|
85
|
+
yield
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
def fetch_map
|
90
|
+
map,value = self.map,self.value
|
91
|
+
unless map.key? value
|
92
|
+
parse_error('is not valid')
|
93
|
+
else
|
94
|
+
map.fetch value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def parse_error(message)
|
100
|
+
raise ParseError.new("#{name}: value #{value.inspect} #{message}")
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
|
105
|
+
def execute(name,value)
|
106
|
+
parser = lookup name
|
107
|
+
parser.execute(value)
|
108
|
+
end
|
109
|
+
|
110
|
+
def register(name,map=nil,&block)
|
111
|
+
if has_parser? name
|
112
|
+
raise ArgumentError,"a parser named #{name.inspect} is already registred"
|
113
|
+
end
|
114
|
+
parser = self.new(name,map,block)
|
115
|
+
registry[name]=parser
|
116
|
+
end
|
117
|
+
|
118
|
+
def lookup(name)
|
119
|
+
registry[name] || raise(ArgumentError,"a parser named #{name.inspect} is not registred")
|
120
|
+
end
|
121
|
+
|
122
|
+
alias :[] :lookup
|
123
|
+
|
124
|
+
def has_parser?(name)
|
125
|
+
registry.key? name
|
126
|
+
end
|
127
|
+
|
128
|
+
def reset!
|
129
|
+
@registry = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
def names
|
133
|
+
registry.keys
|
134
|
+
end
|
135
|
+
|
136
|
+
protected
|
137
|
+
|
138
|
+
def registry
|
139
|
+
@registry ||= {}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser do
|
4
|
+
before :all do
|
5
|
+
DumpParser.register :simple_map, {
|
6
|
+
'a' => 'A',
|
7
|
+
'b' => 'B',
|
8
|
+
'c' => 'C'
|
9
|
+
}
|
10
|
+
|
11
|
+
DumpParser.register :dd_mm_yyyy_datetime do
|
12
|
+
nil_if_empty
|
13
|
+
require_format /\A(\d{2})\.(\d{2})\.(\d{4})\Z/
|
14
|
+
begin
|
15
|
+
DateTime.new match[3].to_i, match[2].to_i, match[1].to_i
|
16
|
+
rescue ArgumentError
|
17
|
+
parse_error 'is an invalid date'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
DumpParser.register :required_integer do
|
22
|
+
require_format /\A(?:\d+)\Z/
|
23
|
+
value.to_i(10)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute(value)
|
28
|
+
DumpParser.execute name,value
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'simple_map' do
|
32
|
+
let(:name) { :simple_map }
|
33
|
+
specify do
|
34
|
+
execute('a').should == 'A'
|
35
|
+
execute('b').should == 'B'
|
36
|
+
execute('c').should == 'C'
|
37
|
+
expect { execute 'unkown' }.to raise_error(DumpParser::ParseError,'simple_map: value "unkown" is not valid')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'dd_mm_yyyy_datetime' do
|
42
|
+
let(:name) { :dd_mm_yyyy_datetime }
|
43
|
+
specify do
|
44
|
+
execute('10.01.1901').should == DateTime.new(1901,1,10)
|
45
|
+
expect { execute 'unkown' }.to raise_error(DumpParser::ParseError,'dd_mm_yyyy_datetime: value "unkown" does not match required format')
|
46
|
+
expect { execute '31.02.1901' }.to raise_error(DumpParser::ParseError,'dd_mm_yyyy_datetime: value "31.02.1901" is an invalid date')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'dump-parser'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
require 'reek/spec'
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.include Reek::Spec
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser,'.execute' do
|
4
|
+
let(:object) { described_class }
|
5
|
+
|
6
|
+
let(:name) { :test }
|
7
|
+
let(:value) { 'value' }
|
8
|
+
let(:parser) { Object.new }
|
9
|
+
|
10
|
+
|
11
|
+
it 'should lookup and execute the parser' do
|
12
|
+
DumpParser.should_receive(:lookup).with(name).and_return(parser)
|
13
|
+
parser.should_receive(:execute).with(value).and_return(nil)
|
14
|
+
DumpParser.execute(name,value).should be_nil
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser,'.has_parser?' do
|
4
|
+
let(:object) { described_class }
|
5
|
+
let(:name) { :test }
|
6
|
+
|
7
|
+
before do
|
8
|
+
object.reset!
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { object.has_parser? name }
|
12
|
+
|
13
|
+
context 'when parser with name exists' do
|
14
|
+
before do
|
15
|
+
object.register name, {}
|
16
|
+
end
|
17
|
+
|
18
|
+
it { should be_true }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when parser with name does not exist' do
|
22
|
+
it { should be_false }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe DumpParser do
|
3
|
+
let(:object) { described_class }
|
4
|
+
let(:parser) { object.register name, {} }
|
5
|
+
|
6
|
+
|
7
|
+
let(:name) { :test }
|
8
|
+
|
9
|
+
let(:lookup_name) { name }
|
10
|
+
|
11
|
+
|
12
|
+
before :each do
|
13
|
+
object.reset!
|
14
|
+
parser
|
15
|
+
end
|
16
|
+
|
17
|
+
subject { object.lookup lookup_name }
|
18
|
+
|
19
|
+
context 'when requested parser was not registred' do
|
20
|
+
let(:lookup_name) { :unkown }
|
21
|
+
specify do
|
22
|
+
expect { subject }.to raise_error(ArgumentError,'a parser named :unkown is not registred')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when requested parser was registred' do
|
27
|
+
it { should == parser }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser, '.names' do
|
4
|
+
let(:object) { described_class }
|
5
|
+
let(:subject) { object.names }
|
6
|
+
|
7
|
+
before do
|
8
|
+
DumpParser.reset!
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
context 'when a parser named :test was registred' do
|
13
|
+
before do
|
14
|
+
object.register :test, {}
|
15
|
+
end
|
16
|
+
|
17
|
+
it { should == [:test] }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when no parser was registred' do
|
21
|
+
it { should == [] }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when many parsers where registred' do
|
25
|
+
before do
|
26
|
+
object.register :a, {}
|
27
|
+
object.register :b, {}
|
28
|
+
object.register :c, {}
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return parser names in registration order' do
|
32
|
+
should == [:a,:b,:c]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser, '.new' do
|
4
|
+
subject { object.new(*arguments) }
|
5
|
+
|
6
|
+
let(:name) { :test }
|
7
|
+
let(:map) { {} }
|
8
|
+
let(:block) { lambda {} }
|
9
|
+
|
10
|
+
let(:object) { described_class }
|
11
|
+
|
12
|
+
shared_examples_for 'a dump parser' do
|
13
|
+
it { should be_instance_of(object) }
|
14
|
+
its(:name) { should == name }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with name and map' do
|
18
|
+
let(:arguments) { [name,map] }
|
19
|
+
|
20
|
+
it_should_behave_like 'a dump parser'
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with name map and block' do
|
24
|
+
let(:arguments) { [name,map,block] }
|
25
|
+
|
26
|
+
it_should_behave_like 'a dump parser'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'without name and block' do
|
30
|
+
let(:arguments) { [name] }
|
31
|
+
|
32
|
+
it do
|
33
|
+
expect { subject }.to raise_error(ArgumentError,'need map block or both')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe DumpParser, '.register' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
let(:name) { :test }
|
8
|
+
let(:block) { nil }
|
9
|
+
let(:map) { nil }
|
10
|
+
let(:parser) { Object.new }
|
11
|
+
|
12
|
+
let(:returned_parser) { @returned_parser }
|
13
|
+
|
14
|
+
before do
|
15
|
+
object.reset!
|
16
|
+
object.should_receive(:new).with(name,map,block).and_return(parser)
|
17
|
+
@returned_parser = object.register(name,map,&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
shared_examples_for 'a parser registration' do
|
21
|
+
context 'returned parser' do
|
22
|
+
subject { returned_parser }
|
23
|
+
it { should == parser }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'registry' do
|
27
|
+
subject { object }
|
28
|
+
it { should have_parser name }
|
29
|
+
its(:names) { should include(name) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with block' do
|
34
|
+
let(:block) { lambda { "value" } }
|
35
|
+
it_should_behave_like 'a parser registration'
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with map' do
|
39
|
+
let(:map) { {} }
|
40
|
+
it_should_behave_like 'a parser registration'
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with map and block' do
|
44
|
+
let(:block) { lambda { "value" } }
|
45
|
+
let(:map) { {} }
|
46
|
+
it_should_behave_like 'a parser registration'
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'name was already regsitred' do
|
50
|
+
specify do
|
51
|
+
expect { object.register name,{} }.to raise_error(ArgumentError,"a parser named :test is already registred")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser, '.reset!' do
|
4
|
+
subject { object }
|
5
|
+
let(:object) { DumpParser }
|
6
|
+
let(:name) { :test }
|
7
|
+
|
8
|
+
before do
|
9
|
+
object.register(name) { "value" }
|
10
|
+
object.reset!
|
11
|
+
end
|
12
|
+
|
13
|
+
it { should_not have_parser(name) }
|
14
|
+
its(:names) { should == [] }
|
15
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DumpParser, '#execute' do
|
4
|
+
let(:name) { :test }
|
5
|
+
let(:map) { nil }
|
6
|
+
let(:block) { nil }
|
7
|
+
let(:object) { described_class.new(name,map,block) }
|
8
|
+
|
9
|
+
subject { object.execute(value) }
|
10
|
+
|
11
|
+
after :each do
|
12
|
+
object.send(:value).should be_nil
|
13
|
+
object.instance_variable_get(:'@match').should be_nil
|
14
|
+
object.instance_variable_get(:'@result').should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with map' do
|
18
|
+
let(:map) { { 'a' => 'b' } }
|
19
|
+
|
20
|
+
context 'when value was in map' do
|
21
|
+
let(:value) { 'a' }
|
22
|
+
it { should == 'b' }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when value was not in map' do
|
26
|
+
let(:value) { 'invalid' }
|
27
|
+
specify do
|
28
|
+
expect { subject }.to raise_error(DumpParser::ParseError,'test: value "invalid" is not valid')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with block' do
|
34
|
+
context 'when no string was given' do
|
35
|
+
let(:value) { Object.new }
|
36
|
+
let(:block) { Proc.new {} }
|
37
|
+
specify do
|
38
|
+
expect { subject }.to raise_error(RuntimeError,'+value+ must be kind of String')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'all blocks' do
|
43
|
+
let(:block) { Proc.new { 'test' } }
|
44
|
+
let(:value) { 'test' }
|
45
|
+
it 'should return last expression from block' do
|
46
|
+
should == 'test'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'nil_if_empty' do
|
51
|
+
let(:block) { Proc.new { nil_if_empty } }
|
52
|
+
|
53
|
+
context 'when empty' do
|
54
|
+
let(:value) { '' }
|
55
|
+
it { should == nil }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when not empty' do
|
59
|
+
let(:value) { 'test' }
|
60
|
+
it { should == value }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'in sequence with other actions' do
|
64
|
+
let(:value) { '' }
|
65
|
+
let(:block) { Proc.new { nil_if_empty; require_format /\w+/ } }
|
66
|
+
it 'should stop execution flow' do
|
67
|
+
should be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'error_if_empty' do
|
73
|
+
let(:block) { Proc.new { error_if_empty } }
|
74
|
+
|
75
|
+
context 'when empty' do
|
76
|
+
let(:value) { '' }
|
77
|
+
specify do
|
78
|
+
expect { subject }.to raise_error(DumpParser::ParseError,'test: value "" must not be empty')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when not empty' do
|
83
|
+
let(:value) { 'test' }
|
84
|
+
it { should == value }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'require_format' do
|
89
|
+
let(:pattern) { %r(\Aabc\Z) }
|
90
|
+
let(:block) { pattern = self.pattern; Proc.new { require_format pattern } }
|
91
|
+
|
92
|
+
context 'when match format' do
|
93
|
+
let(:value) { 'abc' }
|
94
|
+
it { should == value }
|
95
|
+
|
96
|
+
it 'should remember match for later processing' do
|
97
|
+
subject
|
98
|
+
object.send(:match).should == pattern.match(value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when not match format' do
|
103
|
+
let(:value) { 'invalid' }
|
104
|
+
specify do
|
105
|
+
expect { subject }.to raise_error(DumpParser::ParseError,'test: value "invalid" does not match required format')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dump-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Markus Schirp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-07-18 00:00:00.000000000 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: &26502400 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *26502400
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: yard
|
28
|
+
requirement: &26497860 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *26497860
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bundler
|
39
|
+
requirement: &26497260 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '1.0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *26497260
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: jeweler
|
50
|
+
requirement: &26496480 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.6'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *26496480
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rcov
|
61
|
+
requirement: &26495840 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *26495840
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: reek
|
72
|
+
requirement: &26495200 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.2'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *26495200
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: roodi
|
83
|
+
requirement: &26494620 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '2.1'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *26494620
|
92
|
+
description: Provides an easy way to manage a huge amount of domain specific string2value
|
93
|
+
conversions. Mostly useful to convert legacy CSV-Fields from strings with domain
|
94
|
+
specific rules
|
95
|
+
email: mbj@seonic.net
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files:
|
99
|
+
- LICENSE.txt
|
100
|
+
- README.rdoc
|
101
|
+
files:
|
102
|
+
- .document
|
103
|
+
- .rspec
|
104
|
+
- Gemfile
|
105
|
+
- Gemfile.lock
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.rdoc
|
108
|
+
- Rakefile
|
109
|
+
- VERSION
|
110
|
+
- dump-parser.gemspec
|
111
|
+
- lib/dump-parser.rb
|
112
|
+
- spec/integration/dump-parser_spec.rb
|
113
|
+
- spec/quality/dump-parser_spec.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
- spec/unit/dump_parser/class_methods/execute_spec.rb
|
116
|
+
- spec/unit/dump_parser/class_methods/has_parser_spec.rb
|
117
|
+
- spec/unit/dump_parser/class_methods/lookup_spec.rb
|
118
|
+
- spec/unit/dump_parser/class_methods/names_spec.rb
|
119
|
+
- spec/unit/dump_parser/class_methods/new_spec.rb
|
120
|
+
- spec/unit/dump_parser/class_methods/register_spec.rb
|
121
|
+
- spec/unit/dump_parser/class_methods/reset_spec.rb
|
122
|
+
- spec/unit/dump_parser/execute_spec.rb
|
123
|
+
- spec/unit/dump_parser_spec.rb
|
124
|
+
has_rdoc: true
|
125
|
+
homepage: http://github.com/mbj/dump-parser
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
segments:
|
139
|
+
- 0
|
140
|
+
hash: 1500261755431801748
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.6.2
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: Simple string2value DSL
|
153
|
+
test_files: []
|