spectro 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +51 -1
- data/lib/spectro.rb +14 -7
- data/lib/spectro/client.rb +12 -2
- data/lib/spectro/compiler.rb +53 -12
- data/lib/spectro/config.rb +22 -4
- data/lib/spectro/database.rb +22 -6
- data/lib/spectro/http_client.rb +26 -0
- data/lib/spectro/mock.rb +3 -5
- data/lib/spectro/spec.rb +16 -4
- data/lib/spectro/spec/parser.rb +36 -14
- data/lib/spectro/spec/rule.rb +8 -1
- data/lib/spectro/spec/signature.rb +12 -4
- data/spectro.png +0 -0
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc30381812690e2250df10dfb5ae634da7856afc
|
4
|
+
data.tar.gz: 74972d706ae592c219e262dcac13cc6962b1bfeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8287affb8337e7db19ff8f349e7e0739e8ee62677f930b29335053d5302ce41847adacb6ed0eae1a8206c07297d53e744c741f30d89ac6c789b344fee46b396f
|
7
|
+
data.tar.gz: 716ad339a11b90203172115493295589bf6ee454f2b73d21c01392bb6da5f0d8b3aaaf6b7782b76f8fe3f735c72798fae4372a9989520b1296229040915ec46b
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Roberto Decurnex
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
1
|
+
![Spectro](spectro.png)
|
2
2
|
|
3
3
|
Specs driven social meta-programming
|
4
4
|
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/spectro.svg)](http://badge.fury.io/rb/spectro)
|
6
|
+
[![Gitter](https://badges.gitter.im/robertodecurnex/spectro.svg)](https://gitter.im/robertodecurnex/spectro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
5
7
|
[![Build Status](https://api.travis-ci.org/robertodecurnex/spectro.png)](https://travis-ci.org/robertodecurnex/spectro)
|
6
8
|
[![Code Climate](https://codeclimate.com/github/robertodecurnex/spectro/badges/gpa.svg)](https://codeclimate.com/github/robertodecurnex/spectro)
|
7
9
|
[![Test Coverage](https://codeclimate.com/github/robertodecurnex/spectro/badges/coverage.svg)](https://codeclimate.com/github/robertodecurnex/spectro)
|
@@ -9,6 +11,8 @@ Specs driven social meta-programming
|
|
9
11
|
|
10
12
|
## Prototype
|
11
13
|
|
14
|
+
Spectro will fetch an algorithm to cover the given spec form its DB and will then define the `#hello` method using it.
|
15
|
+
|
12
16
|
```ruby
|
13
17
|
require 'spectro'
|
14
18
|
|
@@ -29,5 +33,51 @@ spec_for hello String -> String
|
|
29
33
|
```
|
30
34
|
|
31
35
|
```ruby
|
36
|
+
sample = Sample.new
|
37
|
+
|
32
38
|
sample.hello 'Eddie' #=> 'Say Hello to Eddie'
|
33
39
|
```
|
40
|
+
|
41
|
+
## Working with Mocks
|
42
|
+
|
43
|
+
### Scenarios
|
44
|
+
|
45
|
+
* Keep coding while waiting for an algorithm that covers your specs
|
46
|
+
* Using **Spectro** just to mock stuff
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require 'spectro'
|
50
|
+
|
51
|
+
class EmailValidator
|
52
|
+
|
53
|
+
include Spectro
|
54
|
+
|
55
|
+
implements \
|
56
|
+
valid?: [:email]
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
__END__
|
61
|
+
spec_for valid? String -> TrueClass|FalseClass
|
62
|
+
"valid@email.com" -> true
|
63
|
+
"invalidATemail.com" -> false
|
64
|
+
```
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
require 'email_validator' #=> Spectro::Exception::UndefinedMethodDefinition
|
68
|
+
```
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Spectro.configure do |config|
|
72
|
+
config.enable_mocks!
|
73
|
+
end
|
74
|
+
|
75
|
+
require 'email_validator'
|
76
|
+
|
77
|
+
email_validator = EmailValidator.new
|
78
|
+
|
79
|
+
email_validator.valid?("valid@email.com") #=> true
|
80
|
+
email_validator.valid?("invalidATemail.com") #=> false
|
81
|
+
email_validator.valid?("unknown_param@email.com") #=> raise Spectro::Exception::UnkwnonMockResponse
|
82
|
+
|
83
|
+
```
|
data/lib/spectro.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
require 'colorize'
|
1
2
|
require 'digest'
|
2
3
|
require 'forwardable'
|
4
|
+
require 'net/http'
|
3
5
|
require 'singleton'
|
6
|
+
require 'uri'
|
4
7
|
require 'yaml'
|
5
8
|
|
9
|
+
require 'spectro/compiler'
|
6
10
|
require 'spectro/config'
|
7
11
|
require 'spectro/database'
|
8
12
|
require 'spectro/exception'
|
13
|
+
require 'spectro/http_client'
|
9
14
|
require 'spectro/mock'
|
10
15
|
require 'spectro/spec'
|
11
16
|
|
@@ -16,27 +21,27 @@ module Spectro
|
|
16
21
|
def self.included klass
|
17
22
|
klass.extend(ClassMethods)
|
18
23
|
end
|
19
|
-
|
24
|
+
|
20
25
|
# Gives access to the Spectro::Config instance insde the given block
|
21
26
|
#
|
22
27
|
# Usage:
|
23
28
|
# Spectro.configure do |config|
|
24
29
|
# config.enable_mocks!
|
25
30
|
# end
|
26
|
-
def self.configure
|
31
|
+
def self.configure
|
27
32
|
yield Spectro::Config.instance
|
28
33
|
end
|
29
|
-
|
34
|
+
|
30
35
|
module ClassMethods
|
31
36
|
|
32
37
|
# Register the given method name supporting the given parameters.
|
33
38
|
#
|
34
|
-
# Whenever Spectro::Config.mocks_enabled? is true it will try to cover unfulfilled
|
35
|
-
# specs using the
|
39
|
+
# Whenever Spectro::Config.mocks_enabled? is true it will try to cover unfulfilled
|
40
|
+
# specs using the known rules as mocks.
|
36
41
|
#
|
37
|
-
# @param [{String, Symbol=><String, Symbol>}] interfaces hash of method names and required param names
|
42
|
+
# @param [{String, Symbol=><String, Symbol>}] interfaces hash of method names and required param names supported by the method
|
38
43
|
def implements interfaces
|
39
|
-
file_path = caller.first.match(
|
44
|
+
file_path = caller.first.match(/(?:^|#{Dir.pwd}\/)([^\/].*):\d+:in .+/)[1]
|
40
45
|
interfaces.each do |method_name, required_params|
|
41
46
|
λ = Spectro::Database.fetch(file_path, method_name, *required_params) || Spectro::Mock.create(file_path, method_name)
|
42
47
|
|
@@ -50,3 +55,5 @@ module Spectro
|
|
50
55
|
|
51
56
|
end
|
52
57
|
|
58
|
+
# Loads the current project config, if present
|
59
|
+
load '.spectro/config' if File.exist?('.spectro/config')
|
data/lib/spectro/client.rb
CHANGED
@@ -4,13 +4,23 @@ require 'thor'
|
|
4
4
|
module Spectro
|
5
5
|
|
6
6
|
class Client < Thor
|
7
|
-
|
7
|
+
|
8
8
|
desc 'compile', 'Parses the current project looking for unfulfilled specs and looks for suitable lambdas in the repos. It then updates the cache with them.'
|
9
9
|
def compile
|
10
|
-
require 'spectro/compiler'
|
11
10
|
Spectro::Compiler.compile
|
12
11
|
end
|
13
12
|
|
13
|
+
desc 'init', 'Initialize the current folder as an Spectro project, creating all the required files and folders.'
|
14
|
+
option :f, type: :boolean
|
15
|
+
def init
|
16
|
+
Spectro::Compiler.init options
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'upload', 'Uploads the undefined specs to the Hivein order to let the comunnity work and discuss over them.'
|
20
|
+
def upload
|
21
|
+
Spectro::HTTPClient.upload_undefined_specs
|
22
|
+
end
|
23
|
+
|
14
24
|
end
|
15
25
|
|
16
26
|
end
|
data/lib/spectro/compiler.rb
CHANGED
@@ -4,8 +4,8 @@ require 'yaml/store'
|
|
4
4
|
|
5
5
|
module Spectro
|
6
6
|
|
7
|
-
# Spectro
|
8
|
-
# updating the
|
7
|
+
# Spectro::Compiler is in charge of scan the projects and parse its files,
|
8
|
+
# updating the Spectroi's index and dumping information about the missing
|
9
9
|
# implementations (specs without an associated lambda)
|
10
10
|
class Compiler
|
11
11
|
|
@@ -13,32 +13,73 @@ module Spectro
|
|
13
13
|
|
14
14
|
class << self
|
15
15
|
extend Forwardable
|
16
|
-
def_delegators :instance, :compile
|
16
|
+
def_delegators :instance, :compile, :init
|
17
17
|
end
|
18
18
|
|
19
|
-
# Filters the project files keeping those
|
20
|
-
# It
|
21
|
-
# and creates an .spectro/undefined.yml with
|
19
|
+
# Filters the project files keeping those that make use of Spectro.
|
20
|
+
# It then parses them, check for missing implementations
|
21
|
+
# and creates an .spectro/undefined.yml with their specs.
|
22
22
|
#
|
23
23
|
# @return [Spectro::Compiler] self
|
24
|
-
def compile
|
24
|
+
def compile
|
25
|
+
if !Dir.exist?('.spectro')
|
26
|
+
abort "\n" + "This folder has not been initialzed as an Spectro project. Please run ".white.on_red + " spectro init ".white.on_light_black + " before compiling.".white.on_red + "\n\n"
|
27
|
+
end
|
28
|
+
|
25
29
|
undefined_yaml = YAML::Store.new(".spectro/undefined.yml")
|
26
30
|
undefined_yaml.transaction do
|
27
31
|
targets().map do |path|
|
28
32
|
missing_specs = missing_specs_from_file(path)
|
29
33
|
|
30
34
|
next if missing_specs.empty?
|
31
|
-
|
35
|
+
|
32
36
|
undefined_yaml[path] = missing_specs
|
33
37
|
end
|
34
38
|
end
|
35
|
-
|
39
|
+
|
36
40
|
return self
|
37
41
|
end
|
38
42
|
|
43
|
+
# Init the current folder as an Spectro project, creating all the required files and folders
|
44
|
+
# `.spectro` confg file
|
45
|
+
# `.spectro/index.yml` which will hold the mappings between Files/Method names and defined lambdas
|
46
|
+
# `.spectro/undefined.yml` which will hold the collection of spec definitions not yet fulfilled
|
47
|
+
# `.spectro/cache` folder that will hold the source code of the retrieved lambdas
|
48
|
+
#
|
49
|
+
# @return [Spectro::Compiler] self
|
50
|
+
def init options={}
|
51
|
+
if File.exist?('.spectro/config') && !options[:f]
|
52
|
+
abort "\n" + "Project already initialized. If you want to reset the curret setup you can run ".black.on_yellow + " spectro init -f ".white.on_light_black + "\n\n"
|
53
|
+
end
|
54
|
+
|
55
|
+
Dir.exist?('.spectro') || Dir.mkdir('.spectro')
|
56
|
+
Dir.exist?('.spectro/cache') || Dir.mkdir('.spectro/cache')
|
57
|
+
File.open('.spectro/config', 'w') do |file|
|
58
|
+
file.write <<-CONFIG
|
59
|
+
#!/usr/bin/env ruby
|
60
|
+
|
61
|
+
Spectro.configure do |config|
|
62
|
+
# Sets a custom API Hostname if needed
|
63
|
+
# config.api_hostname = 'localhost:9292'
|
64
|
+
#
|
65
|
+
# Instead of failing in case of unfulfilled functions it will try to use the local specs to get a result
|
66
|
+
# config.enable_mocks!
|
67
|
+
end
|
68
|
+
CONFIG
|
69
|
+
end
|
70
|
+
File.open('.spectro/index.yml', 'w') do |file|
|
71
|
+
end
|
72
|
+
File.open('.spectro/undefined.yml', 'w') do |file|
|
73
|
+
end
|
74
|
+
|
75
|
+
puts "\n" + "The project has been successfully initialized".black.on_blue + "\n\n"
|
76
|
+
|
77
|
+
return self
|
78
|
+
end
|
79
|
+
|
39
80
|
private
|
40
81
|
|
41
|
-
# Parse the specs on the given file path and return those
|
82
|
+
# Parse the specs on the given file path and return those
|
42
83
|
# that have not been fulfilled or need to be updated.
|
43
84
|
#
|
44
85
|
# @param [String] path target file path
|
@@ -50,13 +91,13 @@ module Spectro
|
|
50
91
|
end
|
51
92
|
end
|
52
93
|
|
53
|
-
# Filter project's rb files returning an Array of files
|
94
|
+
# Filter project's rb files returning an Array of files
|
54
95
|
# containinig specs to be parsed.
|
55
96
|
#
|
56
97
|
# @return [<String>] array of files to be parsed
|
57
98
|
def targets
|
58
99
|
return %x[ grep -Pzrl --include="*.rb" "^__END__.*\\n.*spec_for" . ].split("\n").collect do |path|
|
59
|
-
path[2..-1]
|
100
|
+
path[2..-1]
|
60
101
|
end
|
61
102
|
end
|
62
103
|
|
data/lib/spectro/config.rb
CHANGED
@@ -2,15 +2,33 @@ module Spectro
|
|
2
2
|
|
3
3
|
class Config
|
4
4
|
|
5
|
+
API_HOSTNAME = 'localhost:9292'
|
6
|
+
|
5
7
|
attr_accessor :mocks_enabled
|
6
|
-
|
8
|
+
|
7
9
|
include Singleton
|
8
10
|
|
9
11
|
class << self
|
10
12
|
extend Forwardable
|
11
|
-
def_delegators :instance, :enable_mocks!, :mocks_enabled?
|
13
|
+
def_delegators :instance, :api_hostname, :api_hostname=, :enable_mocks!, :mocks_enabled?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the API Hostname from the config
|
17
|
+
# or the default if missin
|
18
|
+
#
|
19
|
+
# @return [String] the API Hostname
|
20
|
+
def api_hostname
|
21
|
+
return @api_hostname || API_HOSTNAME
|
12
22
|
end
|
13
|
-
|
23
|
+
|
24
|
+
# Sets a custom API Hostname
|
25
|
+
#
|
26
|
+
# @param [String|NilClass] hostname the custom hostname or `nil` for the default
|
27
|
+
# @return [String|NilClass]
|
28
|
+
def api_hostname= hostname
|
29
|
+
@api_hostname = hostname
|
30
|
+
end
|
31
|
+
|
14
32
|
# Sets mocks_enabled to true
|
15
33
|
#
|
16
34
|
# @return [Spectro::Config] self
|
@@ -25,7 +43,7 @@ module Spectro
|
|
25
43
|
def mocks_enabled?
|
26
44
|
return !!self.mocks_enabled
|
27
45
|
end
|
28
|
-
|
46
|
+
|
29
47
|
end
|
30
48
|
|
31
49
|
end
|
data/lib/spectro/database.rb
CHANGED
@@ -2,9 +2,9 @@ module Spectro
|
|
2
2
|
|
3
3
|
# Gives access to the current collection of
|
4
4
|
# algorithms (lambdas) providing several ways
|
5
|
-
# to fetch specific elements by different
|
5
|
+
# to fetch specific elements by different criteria.
|
6
6
|
class Database
|
7
|
-
|
7
|
+
|
8
8
|
include Singleton
|
9
9
|
|
10
10
|
class << self
|
@@ -17,15 +17,21 @@ module Spectro
|
|
17
17
|
def initialize
|
18
18
|
self.cache = {}
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# Lazy loads the index.yml and returns it
|
22
22
|
#
|
23
23
|
# @return [Hash] the parsed index.yml
|
24
24
|
def index
|
25
|
-
@index ||=
|
25
|
+
return @index ||= load_index()
|
26
26
|
end
|
27
|
-
|
28
|
-
#
|
27
|
+
|
28
|
+
# Sets the index cache to nil
|
29
|
+
# Just in case you want the database to parse the file once again
|
30
|
+
def reset_index
|
31
|
+
@index = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fetches and returns the target lambda based on the
|
29
35
|
# given class, method name and required aprameters.
|
30
36
|
#
|
31
37
|
# @param [String] file_path relative path of the file that requests the lambda
|
@@ -40,6 +46,16 @@ module Spectro
|
|
40
46
|
return self.cache[λ_id] ||= eval(File.read(".spectro/cache/#{λ_id}.rb"))
|
41
47
|
end
|
42
48
|
|
49
|
+
private
|
50
|
+
|
51
|
+
# Loads and returns the current project index or returns
|
52
|
+
# an empty one if not found
|
53
|
+
def load_index
|
54
|
+
return {} if !File.exist?('.spectro/index.yml')
|
55
|
+
|
56
|
+
return YAML.load_file('.spectro/index.yml') || {}
|
57
|
+
end
|
58
|
+
|
43
59
|
end
|
44
60
|
|
45
61
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Spectro
|
2
|
+
|
3
|
+
# Interact with the API exchanging specs and functions
|
4
|
+
class HTTPClient
|
5
|
+
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
class << self
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :instance, :upload_undefined_specs
|
11
|
+
end
|
12
|
+
|
13
|
+
def upload_undefined_specs
|
14
|
+
uri = URI.parse('http://' + Spectro::Config.api_hostname + '/api/specs')
|
15
|
+
file_path = '.spectro/undefined.yml'
|
16
|
+
|
17
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
18
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
19
|
+
request.body = File.read(file_path)
|
20
|
+
|
21
|
+
http.request(request)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/spectro/mock.rb
CHANGED
@@ -16,9 +16,7 @@ module Spectro
|
|
16
16
|
spec.signature.name == method_name.to_s
|
17
17
|
end
|
18
18
|
|
19
|
-
param_names =
|
20
|
-
('a'.ord+index).chr
|
21
|
-
end
|
19
|
+
param_names = ('a'..'z').first(spec.signature.params_types.count)
|
22
20
|
|
23
21
|
responses = spec.rules.inject({}) do |memo, rule|
|
24
22
|
memo[rule.params] = rule.output
|
@@ -26,13 +24,13 @@ module Spectro
|
|
26
24
|
end
|
27
25
|
|
28
26
|
return eval "
|
29
|
-
|
27
|
+
->(#{param_names.join(',')}) {
|
30
28
|
if !responses.has_key?([#{param_names.join(',')}])
|
31
29
|
raise Spectro::Exception::UnknownMockResponse.new(file_path, method_name)
|
32
30
|
end
|
33
31
|
|
34
32
|
return responses[[#{param_names.join(',')}]]
|
35
|
-
|
33
|
+
}
|
36
34
|
"
|
37
35
|
end
|
38
36
|
|
data/lib/spectro/spec.rb
CHANGED
@@ -5,13 +5,15 @@ require 'spectro/spec/signature'
|
|
5
5
|
module Spectro
|
6
6
|
|
7
7
|
class Spec
|
8
|
-
|
9
|
-
attr_accessor :md5, :rules, :signature
|
10
|
-
|
8
|
+
|
9
|
+
attr_accessor :md5, :description, :rules, :signature
|
10
|
+
|
11
11
|
# @param [String] spec md5
|
12
12
|
# @param [Spectro::Spec::Signature] signature spec signature
|
13
|
+
# @param [String] description spec's description
|
13
14
|
# @param [<Spectro::Spec::Rule>] rules collection of spec rules
|
14
|
-
def initialize md5, signature, rules
|
15
|
+
def initialize md5, signature, description, rules
|
16
|
+
self.description = description
|
15
17
|
self.md5 = md5
|
16
18
|
self.rules = rules
|
17
19
|
self.signature = signature
|
@@ -19,10 +21,20 @@ module Spectro
|
|
19
21
|
|
20
22
|
def == spec
|
21
23
|
return \
|
24
|
+
self.description == spec.description && \
|
22
25
|
self.signature == spec.signature && \
|
23
26
|
self.rules == spec.rules
|
24
27
|
end
|
25
28
|
|
29
|
+
def to_hash
|
30
|
+
return {
|
31
|
+
md5: self.md5,
|
32
|
+
description: self.description,
|
33
|
+
rules: self.rules.collect(&:to_hash),
|
34
|
+
signature: self.signature.to_hash
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
26
38
|
end
|
27
39
|
|
28
40
|
end
|
data/lib/spectro/spec/parser.rb
CHANGED
@@ -6,16 +6,16 @@ module Spectro
|
|
6
6
|
|
7
7
|
# Parser to get Spectro::Spec instances from the metadata on the program's files
|
8
8
|
class Parser
|
9
|
-
|
9
|
+
|
10
10
|
attr_accessor :file_path
|
11
|
-
|
11
|
+
|
12
12
|
# @param [String] file_path the path of the file to parse
|
13
13
|
def initialize file_path
|
14
14
|
self.file_path = file_path
|
15
15
|
end
|
16
16
|
|
17
17
|
# Create an instance of Spectro::Spec::Parser for the given file path
|
18
|
-
# and
|
18
|
+
# and returns the #parse response (the collection of Spectro::Spec instances
|
19
19
|
# for the given file)
|
20
20
|
#
|
21
21
|
# @param [String] file_path the path of the file to parse
|
@@ -24,7 +24,7 @@ module Spectro
|
|
24
24
|
Spectro::Spec::Parser.new(file_path).parse
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
27
|
+
# Looks for specs on the given file and parses them as Spectro::Specs
|
28
28
|
#
|
29
29
|
# @return [<Spectro::Spec>] collection of specs found in the given file path
|
30
30
|
def parse
|
@@ -32,33 +32,55 @@ module Spectro
|
|
32
32
|
return raw_specs.split('spec_for')[1..-1].map do |raw_spec|
|
33
33
|
self.parse_spec raw_spec
|
34
34
|
end
|
35
|
-
end
|
36
|
-
|
35
|
+
end
|
36
|
+
|
37
37
|
# Parses a raw spec and returns an Spectro::Spec instance
|
38
38
|
#
|
39
39
|
# @param [String] raw_spec raw spec
|
40
40
|
# @return [Spectro::Spec] the Spectro::Spec instance
|
41
41
|
def parse_spec raw_spec
|
42
|
-
spec_raw_signature, *
|
43
|
-
|
42
|
+
spec_raw_signature, *spec_raw_desc_and_rules = raw_spec.split("\n").reject(&:empty?)
|
43
|
+
|
44
44
|
spec_signature = self.parse_spec_signature(spec_raw_signature)
|
45
45
|
|
46
|
+
spec_raw_description = spec_raw_desc_and_rules.take_while do |desc_or_rule|
|
47
|
+
desc_or_rule.match(/^`/)
|
48
|
+
end
|
49
|
+
|
50
|
+
spec_description = self.parse_spec_description(spec_raw_description)
|
51
|
+
|
52
|
+
spec_raw_rules = spec_raw_desc_and_rules - spec_raw_description
|
53
|
+
|
46
54
|
spec_rules = spec_raw_rules.map do |spec_raw_rule|
|
47
55
|
self.parse_spec_rule(spec_raw_rule)
|
48
56
|
end
|
49
57
|
|
50
58
|
spec_md5 = Digest::MD5.hexdigest(raw_spec)
|
51
59
|
|
52
|
-
return Spectro::Spec.new(spec_md5, spec_signature, spec_rules)
|
60
|
+
return Spectro::Spec.new(spec_md5, spec_signature, spec_description, spec_rules)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the spec description from the raw spec description
|
64
|
+
#
|
65
|
+
# @param [String] spec_raw_description spec's raw description
|
66
|
+
# @return [String] spec description
|
67
|
+
def parse_spec_description(spec_raw_description)
|
68
|
+
return spec_raw_description.collect do |raw_description|
|
69
|
+
if raw_description[1..-1].empty?
|
70
|
+
next "\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
next raw_description[1..-1].strip
|
74
|
+
end.join(' ').strip.gsub("\n ", "\n")
|
53
75
|
end
|
54
76
|
|
55
|
-
# Returns
|
77
|
+
# Returns an Spectro::Spec::Rule instance from the raw spec rule
|
56
78
|
#
|
57
|
-
# @param [String] spec_raw_rule raw rule
|
58
|
-
# @return [Spectro::Spec::Rule]
|
79
|
+
# @param [String] spec_raw_rule raw rule of the spec
|
80
|
+
# @return [Spectro::Spec::Rule] spec rule instance
|
59
81
|
def parse_spec_rule spec_raw_rule
|
60
82
|
# REGEX HERE PLEASE, F%#&!@* EASY
|
61
|
-
raw_params, raw_output = spec_raw_rule.split('->').map(&:strip)
|
83
|
+
raw_params, raw_output = spec_raw_rule.split('->').map(&:strip)
|
62
84
|
output = eval(raw_output)
|
63
85
|
params = raw_params.split(/,\s+/).map do |raw_param|
|
64
86
|
eval(raw_param)
|
@@ -70,7 +92,7 @@ module Spectro
|
|
70
92
|
# Returns a Spectro::Spec::Signature from the raw spec signature
|
71
93
|
#
|
72
94
|
# @param [String] spec_raw_signature raw signature of the spec
|
73
|
-
# @param [<Spectro::Spec::Signature]
|
95
|
+
# @param [<Spectro::Spec::Signature] spec signature instance
|
74
96
|
def parse_spec_signature spec_raw_signature
|
75
97
|
# REGEX HERE PLEASE, F%#&!@* EASY
|
76
98
|
raw_name_and_params_types, output_type = spec_raw_signature.split('->').map(&:strip)
|
data/lib/spectro/spec/rule.rb
CHANGED
@@ -7,7 +7,7 @@ module Spectro
|
|
7
7
|
class Rule
|
8
8
|
|
9
9
|
attr_accessor :output, :params
|
10
|
-
|
10
|
+
|
11
11
|
# @param [<Object>] parmas set of input params
|
12
12
|
# @param [<Object>] output expected result
|
13
13
|
def initialize params, output
|
@@ -21,6 +21,13 @@ module Spectro
|
|
21
21
|
self.params == rule.params
|
22
22
|
end
|
23
23
|
|
24
|
+
def to_hash
|
25
|
+
return {
|
26
|
+
output: self.output,
|
27
|
+
params: self.params
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
24
31
|
end
|
25
32
|
|
26
33
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Spectro
|
2
2
|
|
3
3
|
class Spec
|
4
|
-
|
5
|
-
# Representation of the required input/output types
|
4
|
+
|
5
|
+
# Representation of the required input/output types
|
6
6
|
class Signature
|
7
|
-
|
7
|
+
|
8
8
|
attr_accessor :name, :output_type, :params_types
|
9
|
-
|
9
|
+
|
10
10
|
# @param [String] name local name of the algorith (not sure if needed)
|
11
11
|
# @param [<String>] param_types types of the expected input params
|
12
12
|
# @param [String] output_type type of the expected output
|
@@ -23,6 +23,14 @@ module Spectro
|
|
23
23
|
self.params_types == signature.params_types
|
24
24
|
end
|
25
25
|
|
26
|
+
def to_hash
|
27
|
+
return {
|
28
|
+
name: self.name,
|
29
|
+
output_type: self.output_type,
|
30
|
+
params_type: self.params_types
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
26
34
|
end
|
27
35
|
|
28
36
|
end
|
data/spectro.png
ADDED
Binary file
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spectro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Decurnex
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: thor
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,8 +128,11 @@ executables:
|
|
114
128
|
- spectro
|
115
129
|
extensions: []
|
116
130
|
extra_rdoc_files:
|
131
|
+
- LICENSE
|
117
132
|
- README.md
|
133
|
+
- spectro.png
|
118
134
|
files:
|
135
|
+
- LICENSE
|
119
136
|
- README.md
|
120
137
|
- bin/spectro
|
121
138
|
- lib/spectro.rb
|
@@ -126,11 +143,13 @@ files:
|
|
126
143
|
- lib/spectro/exception.rb
|
127
144
|
- lib/spectro/exception/undefined_method_definition.rb
|
128
145
|
- lib/spectro/exception/unknown_mock_response.rb
|
146
|
+
- lib/spectro/http_client.rb
|
129
147
|
- lib/spectro/mock.rb
|
130
148
|
- lib/spectro/spec.rb
|
131
149
|
- lib/spectro/spec/parser.rb
|
132
150
|
- lib/spectro/spec/rule.rb
|
133
151
|
- lib/spectro/spec/signature.rb
|
152
|
+
- spectro.png
|
134
153
|
homepage: http://github.com/robertodecurnex/spectro
|
135
154
|
licenses:
|
136
155
|
- MIT
|
@@ -151,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
170
|
version: '0'
|
152
171
|
requirements: []
|
153
172
|
rubyforge_project:
|
154
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.6.2
|
155
174
|
signing_key:
|
156
175
|
specification_version: 4
|
157
176
|
summary: Specs driven social meta-programming
|