booby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 580e3da73af31344e0932d62b61c2eca1d96e581
4
+ data.tar.gz: 0a30866d2bafcfbb14f93ca38d6b83eec8155d19
5
+ SHA512:
6
+ metadata.gz: 2c0389b02e6628b40c99fc7fa57a987d23b6082a4a88b890c12640e42109c27c561a0f9106bb940856ff05643d9c5915676e4a46e1b53153e9c9c80a8cc7021e
7
+ data.tar.gz: ad3468bf0e854b5b1fc776af68c3862bf4573e2352565bd9366ba9b7a05bce99260f91372369cf071fa927a0399a64e11bb1745b1019ff9bca5b63cb82a3cc51
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ \#*
19
+ .\#*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in booby.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Hmurca Team
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ # Booby
2
+
3
+ *Booby* is a super simple and stupid file parser scaffold. It parses very simple
4
+ config files into set of lines (commands with arguments) that are passed to actual
5
+ parser classes (processors).
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'booby'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install booby
20
+
21
+ ## Usage
22
+
23
+ Check project documentation [here](http://docs.hmurca.com/en/latest/booby.html).
24
+
25
+ ## Contributing
26
+
27
+ 1. Work on your changes in a feature branch.
28
+ 2. Make sure that tests are passing.
29
+ 3. Send a pull request.
30
+ 4. Wait for feedback.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "lib"
6
+ t.pattern = "test/*_test.rb"
7
+ t.verbose = false
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,24 @@
1
+ # -*- mode: ruby -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'booby/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "booby"
8
+ spec.version = Booby::VERSION
9
+ spec.authors = ["Hmurca Team"]
10
+ spec.email = ["dev@hmurca.com"]
11
+ spec.description = %q{Stupid config files parser scaffold.}
12
+ spec.summary = %q{Booby is a config files parser scaffold.}
13
+ spec.homepage = "http://docs.hmurca.com/en/latest/booby.html"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,24 @@
1
+ require "booby/version"
2
+
3
+ module Booby
4
+ require "booby/errors"
5
+ require "booby/parser"
6
+
7
+ # Public: Initializes a parser with given source code.
8
+ #
9
+ # source - The String source code of a config file.
10
+ #
11
+ # Returns initialized Parser.
12
+ def self.prepare(source)
13
+ return Parser.new(source)
14
+ end
15
+
16
+ # Public: Initializes a parser with loaded source code.
17
+ #
18
+ # source - The String file name to load.
19
+ #
20
+ # Returns initialized Parser.
21
+ def self.open(fname)
22
+ return Parser.new(File.read(fname))
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ module Booby
2
+ # Public: General error class.
3
+ class Error < StandardError
4
+ end
5
+
6
+ # Public: Error raised when processor returns unexpected stuff.
7
+ class InvalidResponseError < Error
8
+ def initialize(obj)
9
+ super(
10
+ "Invalid response from processor. Expected `true', `false'" +
11
+ "or an instance of processor, got: #{obj.inspect}"
12
+ )
13
+ end
14
+ end
15
+
16
+ # Public: Error raised when processor stumbles upon an unsupported option.
17
+ class UnsupportedOptionError < Error
18
+ def initialize(cmd, line_no)
19
+ super("Unsupported option (line #{line_no}): #{cmd}")
20
+ end
21
+ end
22
+
23
+ # Public: Error raised when arity check fails.
24
+ class InvalidNumberOfParametersError < Error
25
+ def initialize(expected, actual, cmd, line_no)
26
+ expected = "minimum 1" if expected === true
27
+ super(
28
+ "Invalid number of parameters (line #{line_no}): "+
29
+ "#{cmd} expects #{expected} parameter(s), got #{actual}"
30
+ )
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,84 @@
1
+ module Booby
2
+ # Public: Generic configuration parser. You shouldn't access this
3
+ # class directly, use Booby#open and Booby#prepare instead.
4
+ class Parser
5
+ # Public: Initializer.
6
+ #
7
+ # source - The String source code of a config file.
8
+ #
9
+ def initialize(source)
10
+ @source = source
11
+ end
12
+
13
+ # Public: Parses initialized config source with using given processor
14
+ # class. The processor class must implement #process instance method.
15
+ #
16
+ # processor - The processor class to parse source with.
17
+ #
18
+ # Returns processor instance that contains parsed data.
19
+ def parse_with(processor)
20
+ processor.new.tap do |p|
21
+ @__root_processor = @__current_processor = p
22
+ @source.split(/$/).each_with_index { |line, i| process_line(line, i) }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # Internal: Processes single line from source file.
29
+ #
30
+ # line - The String line to be processed.
31
+ # line_no - The Integer current line number.
32
+ #
33
+ # Returns nothing.
34
+ def process_line(line, line_no)
35
+ line.strip!
36
+
37
+ return if line =~ /^\#/ # Skip comment lines...
38
+
39
+ if line.empty?
40
+ # Skip empty line and close recent processing group (if any)...
41
+ @__current_processor = @__root_processor
42
+ return
43
+ end
44
+
45
+ cmd, *args = line.split
46
+
47
+ # Check arity for this command...
48
+ arity = @__current_processor.class.const_get(:ARITY) rescue nil
49
+ arity = arity[cmd] if arity
50
+
51
+ case arity
52
+ when true
53
+ if args.empty?
54
+ raise InvalidNumberOfParametersError.new(
55
+ arity, args.size, cmd, line_no
56
+ )
57
+ end
58
+ when Integer
59
+ if args.size != arity
60
+ raise InvalidNumberOfParametersError.new(
61
+ arity, args.size, cmd, line_no
62
+ )
63
+ end
64
+ end
65
+
66
+ # Parse...
67
+ res = @__current_processor.process(cmd, *args)
68
+
69
+ # Check result...
70
+ case res
71
+ when true
72
+ return
73
+ when false
74
+ raise UnsupportedOptionError.new(cmd, line_no)
75
+ else
76
+ unless res.respond_to?(:process)
77
+ raise InvalidResponseError.new(res)
78
+ end
79
+
80
+ @__current_processor = res
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module Booby
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "minitest/autorun"
2
+ require "fileutils"
3
+ require "booby"
4
+
5
+ $test_tmp_dir = File.expand_path("../../tmp", __FILE__)
6
+ FileUtils.mkdir_p($test_tmp_dir)
@@ -0,0 +1,256 @@
1
+ require File.expand_path("../helper.rb", __FILE__)
2
+
3
+ class SimpleProcessor
4
+ attr_reader :foo, :bar
5
+
6
+ def process(cmd, *args)
7
+ case cmd
8
+ when "foo"
9
+ @foo = args
10
+ when "bar"
11
+ @bar = args
12
+ else
13
+ return false
14
+ end
15
+
16
+ true
17
+ end
18
+ end
19
+
20
+ SIMPLE_FILE = <<END
21
+ foo 1
22
+ bar 1 2
23
+ foo 1 2 3
24
+ END
25
+
26
+ SIMPLE_FILE_WITH_COMMENTS = <<END
27
+ foo 1
28
+ # this is a comment
29
+ bar 1 2
30
+
31
+ # and another one
32
+ # and another...
33
+ foo 1 2 3
34
+ END
35
+
36
+ class GroupProcessor
37
+ attr_reader :foos
38
+
39
+ def process(cmd, *args)
40
+ case cmd
41
+ when "foo"
42
+ @foos ||= []
43
+ @foos << args.first
44
+ else
45
+ return false
46
+ end
47
+
48
+ true
49
+ end
50
+ end
51
+
52
+ class GroupedProcessor
53
+ attr_reader :group, :bar
54
+
55
+ def process(cmd, *args)
56
+ case cmd
57
+ when "bar"
58
+ @bar = args
59
+ when "group"
60
+ @group = GroupProcessor.new
61
+ return @group
62
+ else
63
+ return false
64
+ end
65
+
66
+ true
67
+ end
68
+ end
69
+
70
+ class InvalidGroupedProcessor
71
+ attr_reader :group, :bar
72
+
73
+ def process(cmd, *args)
74
+ case cmd
75
+ when "bar"
76
+ @bar = args
77
+ when "group"
78
+ return Object.new
79
+ else
80
+ return false
81
+ end
82
+
83
+ true
84
+ end
85
+ end
86
+
87
+ ONE_GROUP_FILE = <<END
88
+ bar 1 2
89
+
90
+ group
91
+ foo 3
92
+ foo 4
93
+ END
94
+
95
+ class RepeatableGroupedProcessor
96
+ attr_reader :group, :bar
97
+
98
+ def process(cmd, *args)
99
+ case cmd
100
+ when "bar"
101
+ @bar = args
102
+ when "group"
103
+ @group ||= []
104
+ @group << (g = GroupProcessor.new)
105
+ return g
106
+ else
107
+ return false
108
+ end
109
+
110
+ true
111
+ end
112
+ end
113
+
114
+ REPEATED_GROUP_FILE = <<END
115
+ bar 0
116
+
117
+ group
118
+ foo 3
119
+ foo 4
120
+
121
+ bar 1 2
122
+
123
+ group
124
+ foo 5
125
+ foo 6
126
+ END
127
+
128
+ class InvalidResponseProcessor
129
+ def process(cmd, *args)
130
+ return "foo"
131
+ end
132
+ end
133
+
134
+ UNSUPPORTED_OPTION_FILE = <<END
135
+ foo 1 2
136
+ baz 1
137
+ END
138
+
139
+ class ArityCheckProcessor
140
+ ARITY = {
141
+ 'foo' => 1,
142
+ 'baz' => true
143
+ }
144
+
145
+ attr_reader :foo, :bar, :baz
146
+
147
+ def process(cmd, *args)
148
+ case cmd
149
+ when "foo"
150
+ @foo = args
151
+ when "bar"
152
+ @bar = args
153
+ when "baz"
154
+ @baz = args
155
+ else
156
+ return false
157
+ end
158
+
159
+ true
160
+ end
161
+ end
162
+
163
+ WRONG_ARITY_FILE_1 = <<END
164
+ foo 1 2
165
+ bar 1 2
166
+ baz 1 2 3 4
167
+ END
168
+
169
+ WRONG_ARITY_FILE_2 = <<END
170
+ foo 1
171
+ bar 1 2
172
+ baz
173
+ END
174
+
175
+ CORRECT_ARITY_FILE = <<END
176
+ foo 1
177
+ bar 1 2 3 4
178
+ baz 1 2 3 4
179
+ END
180
+
181
+
182
+ class TestParser < Minitest::Test
183
+ def test_simple_processing
184
+ b = Booby.prepare(SIMPLE_FILE)
185
+ parsed = b.parse_with(SimpleProcessor)
186
+ assert_equal %w{1 2 3}, parsed.foo
187
+ assert_equal %w{1 2}, parsed.bar
188
+ end
189
+
190
+ def test_simple_processing_with_comments
191
+ b = Booby.prepare(SIMPLE_FILE_WITH_COMMENTS)
192
+ parsed = b.parse_with(SimpleProcessor)
193
+ assert_equal %w{1 2 3}, parsed.foo
194
+ assert_equal %w{1 2}, parsed.bar
195
+ end
196
+
197
+ def test_basic_groups_processing
198
+ b = Booby.prepare(ONE_GROUP_FILE)
199
+ parsed = b.parse_with(GroupedProcessor)
200
+ assert_equal %w{1 2}, parsed.bar
201
+ assert_equal %w{3 4}, parsed.group.foos
202
+ end
203
+
204
+ def test_multiple_groups
205
+ b = Booby.prepare(REPEATED_GROUP_FILE)
206
+ parsed = b.parse_with(RepeatableGroupedProcessor)
207
+ assert_equal %w{1 2}, parsed.bar
208
+ assert_equal %w{3 4}, parsed.group[0].foos
209
+ assert_equal %w{5 6}, parsed.group[1].foos
210
+ end
211
+
212
+ def test_invalid_response
213
+ b = Booby.prepare(ONE_GROUP_FILE)
214
+ assert_raises Booby::InvalidResponseError do
215
+ b.parse_with(InvalidResponseProcessor)
216
+ end
217
+ end
218
+
219
+ def test_unsupported_option
220
+ b = Booby.prepare(UNSUPPORTED_OPTION_FILE)
221
+ assert_raises Booby::UnsupportedOptionError do
222
+ b.parse_with(SimpleProcessor)
223
+ end
224
+ end
225
+
226
+ def test_file_opening
227
+ testfile = "./tmp/test.conf"
228
+ File.open(testfile, "w+") { |f| f.puts(SIMPLE_FILE) }
229
+ b = Booby.open(testfile)
230
+ parsed = b.parse_with(SimpleProcessor)
231
+ assert_equal %w{1 2 3}, parsed.foo
232
+ assert_equal %w{1 2}, parsed.bar
233
+ end
234
+
235
+ def test_strict_arity_checking_fail
236
+ b = Booby.prepare(WRONG_ARITY_FILE_1)
237
+ assert_raises Booby::InvalidNumberOfParametersError do
238
+ parsed = b.parse_with(ArityCheckProcessor)
239
+ end
240
+ end
241
+
242
+ def test_minimum_arity_checking_fail
243
+ b = Booby.prepare(WRONG_ARITY_FILE_2)
244
+ assert_raises Booby::InvalidNumberOfParametersError do
245
+ parsed = b.parse_with(ArityCheckProcessor)
246
+ end
247
+ end
248
+
249
+ def test_arity_checking_success
250
+ b = Booby.prepare(CORRECT_ARITY_FILE)
251
+ parsed = b.parse_with(ArityCheckProcessor)
252
+ assert_equal %w{1}, parsed.foo
253
+ assert_equal %w{1 2 3 4}, parsed.bar
254
+ assert_equal %w{1 2 3 4}, parsed.bar
255
+ end
256
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path("../helper.rb", __FILE__)
2
+
3
+ class TestVersion < Minitest::Test
4
+ def test_version_number
5
+ assert_equal Booby::VERSION, "0.0.1"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: booby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hmurca Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Stupid config files parser scaffold.
56
+ email:
57
+ - dev@hmurca.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - booby.gemspec
68
+ - lib/booby.rb
69
+ - lib/booby/errors.rb
70
+ - lib/booby/parser.rb
71
+ - lib/booby/version.rb
72
+ - test/helper.rb
73
+ - test/parser_test.rb
74
+ - test/version_test.rb
75
+ homepage: http://docs.hmurca.com/en/latest/booby.html
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.0.6
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Booby is a config files parser scaffold.
99
+ test_files:
100
+ - test/helper.rb
101
+ - test/parser_test.rb
102
+ - test/version_test.rb