est 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,3 @@
1
+ default: --format pretty
2
+ travis: --format progress
3
+ html_report: --format progress --format html --out=features_report.html
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2014 TechnoPark Corp.
4
+ # Copyright (c) 2014 Yegor Bugayenko
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the 'Software'), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in all
14
+ # copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ lib = File.expand_path('../lib', __FILE__)
25
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
26
+ require 'est/version'
27
+
28
+ Gem::Specification.new do |s|
29
+ s.specification_version = 2 if s.respond_to? :specification_version=
30
+ if s.respond_to? :required_rubygems_version=
31
+ s.required_rubygems_version = Gem::Requirement.new('>= 0')
32
+ end
33
+ s.rubygems_version = '2.2.2'
34
+ s.required_ruby_version = '>= 1.9.3'
35
+ s.name = 'est'
36
+ s.version = Est::VERSION
37
+ s.license = 'MIT'
38
+ s.summary = 'Estimates Automated'
39
+ s.description = 'Estimate project size'
40
+ s.authors = ['Yegor Bugayenko']
41
+ s.email = 'yegor@teamed.io'
42
+ s.homepage = 'http://github.com/teamed/est'
43
+ s.files = `git ls-files`.split($RS)
44
+ s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
45
+ s.test_files = s.files.grep(/^(test|spec|features)\//)
46
+ s.rdoc_options = ['--charset=UTF-8']
47
+ s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
48
+ s.add_runtime_dependency 'nokogiri', '1.6.5'
49
+ s.add_runtime_dependency 'ruby-filemagic', '0.6.1'
50
+ s.add_runtime_dependency 'slop', '3.6.0'
51
+ s.add_runtime_dependency 'rake', '10.4.2'
52
+ s.add_development_dependency 'coveralls', '0.7.2'
53
+ s.add_development_dependency 'rdoc', '4.2.0'
54
+ s.add_development_dependency 'cucumber', '1.3.17'
55
+ s.add_development_dependency 'minitest', '5.5.0'
56
+ s.add_development_dependency 'rubocop', '0.24.1'
57
+ s.add_development_dependency 'rubocop-rspec', '1.2.1'
58
+ s.add_development_dependency 'rspec-rails', '3.1.0'
59
+ end
@@ -0,0 +1,51 @@
1
+ Feature: Command Line Processing
2
+ As an estimator I want to be able to
3
+ call Est as a command line tool
4
+
5
+ Scenario: Help can be printed
6
+ When I run bin/est with "-h"
7
+ Then Exit code is zero
8
+ And Stdout contains "-v, --verbose"
9
+
10
+ Scenario: Version can be printed
11
+ When I run bin/est with "--version"
12
+ Then Exit code is zero
13
+
14
+ Scenario: Simple estimate calculating
15
+ Given I have a "sample.est" file with content:
16
+ """
17
+ id: 789
18
+ date: 19-08-2014
19
+ author: Yegor Bugayenko
20
+ method: champions.pert
21
+ scope:
22
+ 1: basic Sinatra scaffolding
23
+ 2: front-end HAML files
24
+ 3: SASS stylesheet
25
+ 4: five model classes with unit tests
26
+ 5: PostgreSQL migrations
27
+ 6: Cucumber tests for PostgreSQL
28
+ 7: Capybara tests for HTML front
29
+ 8: CasperJS tests
30
+ 9: achieve 80% test coverage
31
+ champions:
32
+ 7:
33
+ worst-case: 40
34
+ best-case: 10
35
+ most-likely: 18
36
+ 4:
37
+ worst-case: 30
38
+ best-case: 8
39
+ most-likely: 16
40
+ """
41
+ When I run bin/est with "-v -d . -f out.xml"
42
+ Then Exit code is zero
43
+ And Stdout contains "reading ."
44
+ And XML file "out.xml" matches "/estimate[total='54']"
45
+
46
+ Scenario: Rejects unknown options
47
+ Given I have a "test.est" file with content:
48
+ """
49
+ """
50
+ When I run bin/est with "--some-unknown-option"
51
+ Then Exit code is not zero
@@ -0,0 +1,22 @@
1
+ Feature: Gem Package
2
+ As a source code writer I want to be able to
3
+ package the Gem into .gem file
4
+
5
+ Scenario: Gem can be packaged
6
+ Given I have a "execs.rb" file with content:
7
+ """
8
+ #!/usr/bin/env ruby
9
+ require 'rubygems'
10
+ spec = Gem::Specification::load('./spec.rb')
11
+ fail 'no executables' if spec.executables.empty?
12
+ """
13
+ When I run bash with
14
+ """
15
+ set -e
16
+ cd est
17
+ gem build est.gemspec
18
+ gem specification --ruby est-*.gem > ../spec.rb
19
+ cd ..
20
+ ruby execs.rb
21
+ """
22
+ Then Exit code is zero
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2014 TechnoPark Corp.
4
+ # Copyright (c) 2014 Yegor Bugayenko
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the 'Software'), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in all
14
+ # copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'est'
25
+ require 'nokogiri'
26
+ require 'tmpdir'
27
+ require 'slop'
28
+ require 'English'
29
+
30
+ Before do
31
+ @cwd = Dir.pwd
32
+ @dir = Dir.mktmpdir('test')
33
+ FileUtils.mkdir_p(@dir) unless File.exist?(@dir)
34
+ Dir.chdir(@dir)
35
+ @opts = Slop.parse ['-v', '-s', @dir] do
36
+ on 'v', 'verbose'
37
+ on 's', 'source', argument: :required
38
+ end
39
+ end
40
+
41
+ After do
42
+ Dir.chdir(@cwd)
43
+ FileUtils.rm_rf(@dir) if File.exist?(@dir)
44
+ end
45
+
46
+ Given(/^I have a "([^"]*)" file with content:$/) do |file, text|
47
+ FileUtils.mkdir_p(File.dirname(file)) unless File.exist?(file)
48
+ File.open(file, 'w') do |f|
49
+ f.write(text)
50
+ end
51
+ end
52
+
53
+ When(/^I run est$/) do
54
+ @xml = Nokogiri::XML.parse(Est::Base.new(@opts).xml)
55
+ end
56
+
57
+ Then(/^XML matches "([^"]+)"$/) do |xpath|
58
+ fail "XML doesn't match \"#{xpath}\":\n#{@xml}" if @xml.xpath(xpath).empty?
59
+ end
60
+
61
+ When(/^I run est it fails with "([^"]*)"$/) do |txt|
62
+ begin
63
+ Est::Base.new(@opts).xml
64
+ passed = true
65
+ rescue Est::Error => ex
66
+ unless ex.message.include?(txt)
67
+ raise "Est failed but exception doesn't contain \"#{txt}\": #{ex.message}"
68
+ end
69
+ end
70
+ fail "Est didn't fail" if passed
71
+ end
72
+
73
+ When(/^I run bin\/est with "([^"]*)"$/) do |arg|
74
+ home = File.join(File.dirname(__FILE__), '../..')
75
+ @stdout = `ruby -I#{home}/lib #{home}/bin/est #{arg}`
76
+ @exitstatus = $CHILD_STATUS.exitstatus
77
+ end
78
+
79
+ Then(/^Stdout contains "([^"]*)"$/) do |txt|
80
+ unless @stdout.include?(txt)
81
+ fail "STDOUT doesn't contain '#{txt}':\n#{@stdout}"
82
+ end
83
+ end
84
+
85
+ Then(/^Stdout is empty$/) do
86
+ fail "STDOUT is not empty:\n#{@stdout}" unless @stdout == ''
87
+ end
88
+
89
+ Then(/^XML file "([^"]+)" matches "([^"]+)"$/) do |file, xpath|
90
+ fail "File #{file} doesn't exit" unless File.exist?(file)
91
+ xml = Nokogiri::XML.parse(File.read(file))
92
+ xml.remove_namespaces!
93
+ if xml.xpath(xpath).empty?
94
+ fail "XML file #{file} doesn't match \"#{xpath}\":\n#{xml}"
95
+ end
96
+ end
97
+
98
+ Then(/^Exit code is zero$/) do
99
+ fail "Non-zero exit code #{@exitstatus}" unless @exitstatus == 0
100
+ end
101
+
102
+ Then(/^Exit code is not zero$/) do
103
+ fail 'Zero exit code' if @exitstatus == 0
104
+ end
105
+
106
+ When(/^I run bash with$/) do |text|
107
+ FileUtils.copy_entry(@cwd, File.join(@dir, 'est'))
108
+ @stdout = `#{text}`
109
+ @exitstatus = $CHILD_STATUS.exitstatus
110
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2014 TechnoPark Corp.
4
+ # Copyright (c) 2014 Yegor Bugayenko
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the 'Software'), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in all
14
+ # copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'simplecov'
25
+ require 'est'
@@ -0,0 +1,123 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2014 TechnoPark Corp.
4
+ # Copyright (c) 2014 Yegor Bugayenko
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the 'Software'), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in all
14
+ # copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'est/version'
25
+ require 'est/estimates'
26
+ require 'nokogiri'
27
+ require 'logger'
28
+ require 'time'
29
+
30
+ # Est main module.
31
+ # Author:: Yegor Bugayenko (yegor@teamed.io)
32
+ # Copyright:: Copyright (c) 2014 Yegor Bugayenko
33
+ # License:: MIT
34
+ module Est
35
+ # If it breaks.
36
+ class Error < StandardError
37
+ end
38
+
39
+ # If it violates XSD schema.
40
+ class SchemaError < Error
41
+ end
42
+
43
+ # Get logger.
44
+ def self.log
45
+ unless @logger
46
+ @logger = Logger.new(STDOUT)
47
+ @logger.formatter = proc { |severity, _, _, msg|
48
+ "#{severity}: #{msg.dump}\n"
49
+ }
50
+ @logger.level = Logger::ERROR
51
+ end
52
+ @logger
53
+ end
54
+
55
+ class << self
56
+ attr_writer :logger
57
+ end
58
+
59
+ # Code base abstraction
60
+ class Base
61
+ # Ctor.
62
+ # +opts+:: Options
63
+ def initialize(opts)
64
+ @opts = opts
65
+ Est.log.level = Logger::INFO if @opts.verbose?
66
+ Est.log.info "my version is #{Est::VERSION}"
67
+ end
68
+
69
+ # Generate XML.
70
+ def xml
71
+ dir = @opts.dir? ? @opts[:dir] : Dir.pwd
72
+ Est.log.info "reading #{dir}"
73
+ estimates = Estimates.new(dir)
74
+ sanitize(
75
+ Nokogiri::XML::Builder.new do |xml|
76
+ xml << "<?xml-stylesheet type='text/xsl' href='#{xsl}'?>"
77
+ xml.estimate(attrs) do
78
+ xml.total estimates.total
79
+ xml.ests do
80
+ estimates.iterate.each do |est|
81
+ xml.est('id' => est.id) do
82
+ xml.date est.date
83
+ xml.total est.total
84
+ xml.author est.author
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end.to_xml
90
+ )
91
+ end
92
+
93
+ private
94
+
95
+ def attrs
96
+ {
97
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
98
+ 'xsi:noNamespaceSchemaLocation' => "#{host('xsd')}/#{Est::VERSION}.xsd",
99
+ 'version' => Est::VERSION,
100
+ 'date' => Time.now.utc.iso8601
101
+ }
102
+ end
103
+
104
+ def host(suffix)
105
+ "http://est-#{suffix}.teamed.io"
106
+ end
107
+
108
+ def xsl
109
+ "#{host('xsl')}/#{Est::VERSION}.xsl"
110
+ end
111
+
112
+ def sanitize(xml)
113
+ xsd = Nokogiri::XML::Schema(
114
+ File.read(File.join(File.dirname(__FILE__), '../assets/est.xsd'))
115
+ )
116
+ errors = xsd.validate(Nokogiri::XML(xml)).map(&:message)
117
+ errors.each { |e| Est.log.error e }
118
+ Est.log.error(xml) unless errors.empty?
119
+ fail SchemaError, errors.join('; ') unless errors.empty?
120
+ xml
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2014 TechnoPark Corp.
4
+ # Copyright (c) 2014 Yegor Bugayenko
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the 'Software'), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in all
14
+ # copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'est/version'
25
+ require 'est/methods/champions'
26
+ require 'logger'
27
+ require 'yaml'
28
+
29
+ # Single estimate.
30
+ # Author:: Yegor Bugayenko (yegor@teamed.io)
31
+ # Copyright:: Copyright (c) 2014 Yegor Bugayenko
32
+ # License:: MIT
33
+ module Est
34
+ # Estimate.
35
+ class Estimate
36
+ # Ctor.
37
+ # +file+:: File with YAML estimate
38
+ def initialize(file)
39
+ @yaml = YAML.load_file(file)
40
+ fail "failed to read file #{file}" unless @yaml
41
+ end
42
+
43
+ # Get id.
44
+ def id
45
+ @yaml['id']
46
+ end
47
+
48
+ # Get date.
49
+ def date
50
+ Date.strptime(@yaml['date'], '%d-%m-%Y')
51
+ end
52
+
53
+ # Get author.
54
+ def author
55
+ @yaml['author']
56
+ end
57
+
58
+ # Get total estimate.
59
+ def total
60
+ method = @yaml['method']
61
+ fail "unsupported method #{method}" unless method == 'champions.pert'
62
+ Champions.new(@yaml).total
63
+ end
64
+ end
65
+ end