booby 0.0.1

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.
@@ -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