rnfse 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/CHANGELOG.md +0 -0
  6. data/Gemfile +3 -0
  7. data/Guardfile +15 -0
  8. data/LICENSE.md +41 -0
  9. data/Procfile +1 -0
  10. data/README.md +59 -0
  11. data/Rakefile +12 -0
  12. data/lib/provedores.yml +11 -0
  13. data/lib/rnfse/api/abrasf_1_0/definitions.json +374 -0
  14. data/lib/rnfse/api/abrasf_1_0/recepcionar_lote_rps.json +46 -0
  15. data/lib/rnfse/api/abrasf_1_0.rb +55 -0
  16. data/lib/rnfse/api/iss_net_1_0.rb +6 -0
  17. data/lib/rnfse/api.rb +101 -0
  18. data/lib/rnfse/configuration.rb +18 -0
  19. data/lib/rnfse/core.rb +9 -0
  20. data/lib/rnfse/hash.rb +148 -0
  21. data/lib/rnfse/string.rb +36 -0
  22. data/lib/rnfse/version.rb +3 -0
  23. data/lib/rnfse/xml_builder/abrasf_1_0.rb +95 -0
  24. data/lib/rnfse/xml_builder/iss_net_1_0.rb +70 -0
  25. data/lib/rnfse/xml_builder.rb +10 -0
  26. data/lib/rnfse.rb +22 -0
  27. data/rnfse.gemspec +60 -0
  28. data/spec/api/abrasf_1_0/recepcionar_lote_rps_json_spec.rb +123 -0
  29. data/spec/api/abrasf_1_0_spec.rb +26 -0
  30. data/spec/api/iss_net_1_0_spec.rb +99 -0
  31. data/spec/api_spec.rb +65 -0
  32. data/spec/core_spec.rb +35 -0
  33. data/spec/fixtures/abrasf_1_0/enviar_lote_rps_envio.xml +47 -0
  34. data/spec/fixtures/abrasf_1_0/nfse.xsd +771 -0
  35. data/spec/fixtures/certificate.pem +18 -0
  36. data/spec/fixtures/iss_net_1_0/enviar_lote_rps_envio.xml +75 -0
  37. data/spec/fixtures/key.pem +15 -0
  38. data/spec/fixtures/vcr_cassettes/iss_net_1_0_recepcionar_lote_rps.yml +214 -0
  39. data/spec/hash_spec.rb +205 -0
  40. data/spec/spec_helper.rb +29 -0
  41. data/spec/string_spec.rb +38 -0
  42. data/spec/support/.keep +0 -0
  43. data/spec/version_spec.rb +5 -0
  44. data/spec/xml_builder/abrasf_1_0_spec.rb +63 -0
  45. data/spec/xml_builder/iss_net_1_0_spec.rb +86 -0
  46. data/spec/xml_builder_spec.rb +14 -0
  47. metadata +433 -0
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'json-schema'
3
+
4
+ module Rnfse::API::Abrasf10
5
+
6
+ module ClassMethods
7
+
8
+ def recepcionar_lote_rps(hash = {})
9
+ file = get_filepath('recepcionar_lote_rps.json')
10
+ json = Rnfse::Hash.camelize_and_symbolize_keys(hash, false).to_json
11
+ errors = JSON::Validator.fully_validate(file, json)
12
+ if errors.empty?
13
+ xml = xml_builder.build_recepcionar_lote_rps_xml(hash)
14
+ xml.sign!(certificate: File.read(self.certificate), key: File.read(self.key))
15
+ response = self.soap_client.call(
16
+ :recepcionar_lote_rps,
17
+ soap_action: 'RecepcionarLoteRps',
18
+ message_tag: 'RecepcionarLoteRps',
19
+ message: { :'xml!' => "<![CDATA[#{xml}]]>" })
20
+ parse_response(response)
21
+ else
22
+ raise ArgumentError, errors, caller
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def parse_response(response)
29
+ hash = Rnfse::Hash.new(response.body)
30
+ lote_rps_response = hash[:recepcionar_lote_rps_response]
31
+ if !lote_rps_response.empty? and lote_rps_response[:recepcionar_lote_rps_result]
32
+ xml = hash[:recepcionar_lote_rps_response][:recepcionar_lote_rps_result]
33
+ hash[:recepcionar_lote_rps_response][:recepcionar_lote_rps_result] =
34
+ Nori.new.parse(xml)
35
+ end
36
+ hash.underscore_and_symbolize_keys
37
+ end
38
+
39
+ def get_filepath(filename)
40
+ File.join(File.expand_path(File.dirname(__FILE__)), 'abrasf_1_0', filename)
41
+ end
42
+
43
+ end
44
+
45
+ extend ClassMethods
46
+
47
+ def self.extended(base)
48
+ base.extend(ClassMethods)
49
+ end
50
+
51
+ def self.included(base)
52
+ base.send(:include, ClassMethods)
53
+ end
54
+
55
+ end
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'json-schema'
3
+
4
+ module Rnfse::API::IssNet10
5
+ include Rnfse::API::Abrasf10
6
+ end
data/lib/rnfse/api.rb ADDED
@@ -0,0 +1,101 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse
4
+
5
+ class API
6
+ attr_accessor :namespace
7
+ attr_accessor :endpoint
8
+ attr_accessor :api
9
+ attr_accessor :certificate
10
+ attr_accessor :key
11
+ attr_accessor :xml_builder
12
+ attr_accessor :soap_client
13
+ attr_accessor :verbose
14
+
15
+ def initialize(options = {})
16
+ options = load_options(options)
17
+
18
+ file = Pathname.new(File.expand_path('../..', __FILE__))
19
+ provedores = YAML.load_file(file.join('provedores.yml'))
20
+
21
+ case
22
+ when has_options(options, 'provedor', 'homologacao')
23
+ provedor = provedores['homologacao'][options['provedor'].to_s]
24
+ raise ArgumentError, 'provedor de homologação inexistente', caller if provedor.nil?
25
+ self.namespace = provedor['namespace']
26
+ self.endpoint = provedor['endpoint']
27
+ self.api = provedor['api']
28
+
29
+ when has_options(options, 'provedor', 'municipio')
30
+ provedor = provedores['producao'][options['provedor'].to_s]
31
+ raise ArgumentError, 'provedor inexistente', caller if provedor.nil?
32
+ self.namespace = provedor['namespace']
33
+ self.endpoint = provedor['endpoint'] % { municipio: options['municipio'] }
34
+ self.api = provedor['api']
35
+
36
+ when has_options(options, 'padrao', 'namespace', 'endpoint')
37
+ self.namespace = options['namespace'].to_s
38
+ self.endpoint = options['endpoint'].to_s
39
+ self.api = options['padrao'].to_s
40
+
41
+ else
42
+ raise ArgumentError, 'opções inválidas', caller
43
+ end
44
+
45
+ if has_options(options, 'certificate', 'key')
46
+ self.certificate = options['certificate']
47
+ self.key = options['key']
48
+ else
49
+ raise ArgumentError, 'opções de assinatura digital faltando', caller
50
+ end
51
+
52
+ self.verbose = options['verbose'] || false
53
+ self.xml_builder = options['xml_builder'] || XMLBuilder.new(padrao: self.api)
54
+ self.soap_client = options['soap_client'] || savon_client
55
+
56
+ extend self.class.const_get(String.camelize(self.api))
57
+ end
58
+
59
+ private
60
+
61
+ def savon_client
62
+ savon_hash = {
63
+ soap_version: 2,
64
+ env_namespace: :soap,
65
+ namespace_identifier: nil,
66
+ ssl_verify_mode: :peer,
67
+ ssl_cert_file: self.certificate,
68
+ ssl_cert_key_file: self.key,
69
+ endpoint: self.endpoint,
70
+ namespace: self.namespace
71
+ }
72
+
73
+ savon_hash = savon_hash.merge(
74
+ log: true,
75
+ log_level: :debug,
76
+ pretty_print_xml: true
77
+ ) if self.verbose
78
+
79
+ Savon.client(savon_hash)
80
+ end
81
+
82
+ def has_options(hash, *options)
83
+ options.each { |option| return false if hash[option].nil? }
84
+ end
85
+
86
+ def load_options(hash)
87
+ hash = Rnfse::Hash.new(hash)
88
+ hash = hash.stringify_keys
89
+ config = Rnfse::Configuration.instance
90
+
91
+ attrs = ['provedor', 'municipio', 'namespace', 'endpoint',
92
+ 'verbose', 'api', 'certificate', 'key', 'xml_builder',
93
+ 'soap_client', 'verbose', 'homologacao']
94
+ attrs.each do |attr|
95
+ hash[attr] = config.send(attr) if hash[attr].nil?
96
+ end
97
+ hash
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,18 @@
1
+ module Rnfse
2
+ class Configuration
3
+ include Singleton
4
+
5
+ attr_accessor :provedor
6
+ attr_accessor :municipio
7
+ attr_accessor :namespace
8
+ attr_accessor :endpoint
9
+ attr_accessor :homologacao
10
+ attr_accessor :api
11
+ attr_accessor :certificate
12
+ attr_accessor :key
13
+ attr_accessor :xml_builder
14
+ attr_accessor :soap_client
15
+ attr_accessor :verbose
16
+
17
+ end
18
+ end
data/lib/rnfse/core.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Rnfse
2
+ def self.configuration
3
+ Rnfse::Configuration.instance
4
+ end
5
+
6
+ def self.configure
7
+ yield(configuration) if block_given?
8
+ end
9
+ end
data/lib/rnfse/hash.rb ADDED
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse
4
+ class Hash < ::Hash
5
+
6
+ def initialize(constructor = {})
7
+ if constructor.is_a?(::Hash)
8
+ super()
9
+ update(constructor)
10
+ else
11
+ super(constructor)
12
+ end
13
+ end
14
+
15
+ def update(other_hash)
16
+ if other_hash.is_a?(Hash)
17
+ super(other_hash)
18
+ else
19
+ other_hash.to_hash.each_pair do |key, value|
20
+ self[key] = value
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.stringify_keys(obj)
26
+ self.transform_keys(obj) { |key| key.to_s rescue key }
27
+ end
28
+
29
+ def stringify_keys
30
+ self.class.stringify_keys(self)
31
+ end
32
+
33
+ def self.symbolize_keys(obj)
34
+ self.transform_keys(obj) { |key| key.to_sym rescue key }
35
+ end
36
+
37
+ def symbolize_keys
38
+ self.class.symbolize_keys(self)
39
+ end
40
+
41
+ def self.camelize_and_symbolize_keys(obj, uppercase_first_letter = true)
42
+ self.transform_keys(obj) do |key|
43
+ String.camelize(key.to_s, uppercase_first_letter).to_sym rescue key
44
+ end
45
+ end
46
+
47
+ def camelize_and_symbolize_keys(uppercase_first_letter = true)
48
+ self.class.camelize_and_symbolize_keys(self, uppercase_first_letter)
49
+ end
50
+
51
+ def self.underscore_and_symbolize_keys(obj)
52
+ self.transform_keys(obj) do |key|
53
+ String.underscore(key.to_s).to_sym rescue key
54
+ end
55
+ end
56
+
57
+ def underscore_and_symbolize_keys
58
+ self.class.underscore_and_symbolize_keys(self)
59
+ end
60
+
61
+ def self.transform_keys(obj, &block)
62
+ case
63
+ when obj.kind_of?(::Hash)
64
+ result = {}
65
+ obj.each_key do |key|
66
+ result[yield(key)] = self.transform_keys(obj[key], &block)
67
+ end
68
+ result
69
+ when obj.kind_of?(::Array)
70
+ result = []
71
+ obj.each do |elem|
72
+ result << self.transform_keys(elem, &block)
73
+ end
74
+ result
75
+ else
76
+ obj
77
+ end
78
+ end
79
+
80
+ def transform_keys(&block)
81
+ self.class.transform_keys(self, &block)
82
+ end
83
+
84
+ def self.transform_values(obj, key, &block)
85
+ key = /\A#{key}\Z/ unless key.kind_of?(::Regexp)
86
+
87
+ case
88
+ when obj.kind_of?(::Hash)
89
+ result = {}
90
+ obj.each_key do |k|
91
+ if key.match(k)
92
+ result[k] = yield(obj[k])
93
+ else
94
+ result[k] = self.transform_values(obj[k], key, &block)
95
+ end
96
+ end
97
+ result
98
+ when obj.kind_of?(::Array)
99
+ result = []
100
+ obj.each do |elem|
101
+ result << self.transform_values(elem, key, &block)
102
+ end
103
+ result
104
+ else
105
+ obj
106
+ end
107
+ end
108
+
109
+ def transform_values(key, &block)
110
+ self.class.transform_values(self, key, &block)
111
+ end
112
+
113
+ def self.replace_key_values(obj, key, &block)
114
+ parent = key.to_s.split('/').first
115
+ childs = key.to_s.split('/')[1..-1]
116
+ regex = key.kind_of?(::Regexp) ? key : /\A#{parent}\Z/
117
+
118
+ case
119
+ when obj.kind_of?(::Hash)
120
+ result = {}
121
+ obj.each_key do |k|
122
+ case
123
+ when (regex.match(k) and childs.empty?)
124
+ result.merge!(yield(k, obj[k]))
125
+ when (regex.match(k) and !childs.empty?)
126
+ result[k] = self.replace_key_values(obj[k], childs.join('/'), &block)
127
+ else
128
+ result[k] = self.replace_key_values(obj[k], key, &block)
129
+ end
130
+ end
131
+ result
132
+ when obj.kind_of?(::Array)
133
+ result = []
134
+ obj.each do |elem|
135
+ result << self.replace_key_values(elem, key, &block)
136
+ end
137
+ result
138
+ else
139
+ obj
140
+ end
141
+ end
142
+
143
+ def replace_key_values(key, &block)
144
+ self.class.replace_key_values(self, key, &block)
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse
4
+ class String < ::String
5
+ def self.camelize(term, uppercase_first_letter = true)
6
+ string = term.to_s
7
+ if uppercase_first_letter
8
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
9
+ else
10
+ string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { $&.downcase }
11
+ end
12
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { $2.capitalize }
13
+ string.gsub!('/', '::')
14
+ string
15
+ end
16
+
17
+ def camelize
18
+ self.class.camelize(self)
19
+ end
20
+
21
+ def self.underscore(term)
22
+ word = term.to_s.gsub('::', '/')
23
+ word.gsub!(/(?:([A-Za-z\d])|^)(?=\b|[^a-z])/)
24
+ #{ "#{$1}#{$1 && '_'}#{$2.downcase}" }
25
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
26
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
27
+ word.tr!("-", "_")
28
+ word.downcase!
29
+ word
30
+ end
31
+
32
+ def underscore
33
+ self.class.underscore(self)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Rnfse
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse::XMLBuilder::Abrasf10
4
+
5
+ module ClassMethods
6
+
7
+ def build_recepcionar_lote_rps_xml(hash = {})
8
+ hash = prepare_hash(hash)
9
+ inner_xml = ::Gyoku.xml(hash, key_converter: :none)
10
+ xml_builder('EnviarLoteRpsEnvio', inner_xml).doc
11
+ end
12
+
13
+ private
14
+
15
+ # prepara um hash para ser convertido a xml com o Gyoku
16
+ def prepare_hash(hash)
17
+ hash = camelize_hash(hash)
18
+ hash = wrap_rps(hash)
19
+ hash = add_tc_namespace(hash)
20
+ hash = clean_numerics(hash)
21
+ hash = date_to_utc(hash)
22
+ hash = fix_booleans(hash)
23
+ hash
24
+ end
25
+
26
+ # converte booleanos para 1 ou 2
27
+ def fix_booleans(hash)
28
+ regex = /(IssRetido|OptanteSimplesNacional|IncentivadorCultural)\Z/
29
+ Rnfse::Hash.transform_values(hash, regex) do |val|
30
+ val ? 1 : 2
31
+ end
32
+ end
33
+
34
+ # converte datas para GMT-0
35
+ def date_to_utc(hash)
36
+ Rnfse::Hash.transform_values(hash, /DataEmissao\Z/) do |val|
37
+ DateTime.parse(val).new_offset(0).strftime('%FT%T')
38
+ end
39
+ end
40
+
41
+ # limpa tags que por precaução é melhor só conter números
42
+ def clean_numerics(hash)
43
+ regex = /(Cep|Cnae|Cpf|Cnpj)\Z/
44
+ Rnfse::Hash.transform_values(hash, regex) { |val| val.gsub(/\D/, '') }
45
+ end
46
+
47
+ # converte as chaves do hash para CamelCase
48
+ def camelize_hash(hash)
49
+ Rnfse::Hash.camelize_and_symbolize_keys(hash)
50
+ end
51
+
52
+ # encapsula as rps dentro de listaRps com Rps/InfRps
53
+ def wrap_rps(hash)
54
+ hash[:LoteRps][:ListaRps] = {
55
+ :Rps => { :InfRps => hash[:LoteRps][:ListaRps] }
56
+ }
57
+ hash
58
+ end
59
+
60
+ # adiciona o namespace tc nas tags dentro de loteRps
61
+ def add_tc_namespace(hash)
62
+ hash[:LoteRps] = Rnfse::Hash.transform_keys(hash[:LoteRps]) { |key| "tc:#{key}".to_sym }
63
+ hash
64
+ end
65
+
66
+ def xmlns
67
+ 'http://www.abrasf.org.br/servico_enviar_lote_rps_envio.xsd'
68
+ end
69
+
70
+ # namespace dos tipos complexos
71
+ def xmlns_tc
72
+ 'http://www.abrasf.org.br/tipos_complexos.xsd'
73
+ end
74
+
75
+ # instancia o builder a ser utilizado na geracao do xml
76
+ def xml_builder(root, inner_xml)
77
+ Nokogiri::XML::Builder.new(encoding: 'utf-8') do |xml|
78
+ xml.send(root.to_sym, 'xmlns' => xmlns, 'xmlns:tc' => xmlns_tc) do
79
+ xml << inner_xml
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ extend ClassMethods
86
+
87
+ def self.extended(base)
88
+ base.extend(ClassMethods)
89
+ end
90
+
91
+ def self.included(base)
92
+ base.send(:include, ClassMethods)
93
+ end
94
+
95
+ end
@@ -0,0 +1,70 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse::XMLBuilder::IssNet10
4
+ include Rnfse::XMLBuilder::Abrasf10
5
+
6
+ private
7
+
8
+ # prepara um hash para ser convertido a xml com o Gyoku
9
+ def prepare_hash(hash)
10
+ hash = camelize_hash(hash)
11
+ hash = wrap_rps(hash)
12
+ hash = add_tc_namespace(hash)
13
+ hash = clean_numerics(hash)
14
+ hash = date_to_utc(hash)
15
+ hash = fix_booleans(hash)
16
+ hash = wrap_cpf_cnpj(hash)
17
+ hash = add_municipio_prestacao_servico(hash)
18
+ hash = add_estado(hash)
19
+ hash = add_cidade(hash)
20
+ hash = alter_aliquota(hash)
21
+
22
+ hash
23
+ end
24
+
25
+ # alterar o formato da aliquota de 0 a 1 para 0 a 100
26
+ def alter_aliquota(hash)
27
+ Rnfse::Hash.transform_values(hash, 'tc:Aliquota') do |val|
28
+ "%.2f" % (val * 100)
29
+ end
30
+ end
31
+
32
+ # troca a tag Endereco/CodigoMunicipio por Cidade
33
+ def add_cidade(hash)
34
+ Rnfse::Hash.replace_key_values(hash, 'tc:Endereco/tc:CodigoMunicipio') do |key, value|
35
+ { 'tc:Cidade' => value }
36
+ end
37
+ end
38
+
39
+ # troca a tag Uf pela tag Estado
40
+ def add_estado(hash)
41
+ Rnfse::Hash.replace_key_values(hash, 'tc:Uf') do |key, value|
42
+ { :'tc:Estado' => value }
43
+ end
44
+ end
45
+
46
+ # troca a tag CodigoMunicipio para MunicipioPrestacaoServico
47
+ # na tag Servico
48
+ def add_municipio_prestacao_servico(hash)
49
+ Rnfse::Hash.replace_key_values(hash, 'tc:Servico/tc:CodigoMunicipio') do |key, value|
50
+ { :'tc:MunicipioPrestacaoServico' => value }
51
+ end
52
+ end
53
+
54
+ # encapsula as tags cpf ou cnpj em uma tag cpfcnpj
55
+ def wrap_cpf_cnpj(hash)
56
+ regex = /(Cpf|Cnpj)\Z/
57
+ Rnfse::Hash.replace_key_values(hash, regex) do |key, value|
58
+ { :'tc:CpfCnpj' => { key => value } }
59
+ end
60
+ end
61
+
62
+ def xmlns
63
+ 'http://www.issnetonline.com.br/webserviceabrasf/vsd/servico_enviar_lote_rps_envio.xsd'
64
+ end
65
+
66
+ def xmlns_tc
67
+ 'http://www.issnetonline.com.br/webserviceabrasf/vsd/tipos_complexos.xsd'
68
+ end
69
+
70
+ end
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Rnfse
4
+ class XMLBuilder
5
+ def initialize(options)
6
+ options = Hash.stringify_keys(options)
7
+ extend self.class.const_get(String.camelize(options['padrao']))
8
+ end
9
+ end
10
+ end
data/lib/rnfse.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'date'
2
+ require 'pathname'
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'json-schema'
6
+ require 'gyoku'
7
+ require 'nokogiri-xmlsec1'
8
+ require 'savon'
9
+
10
+ require 'rnfse/core'
11
+ require 'rnfse/version'
12
+ require 'rnfse/configuration'
13
+ require 'rnfse/hash'
14
+ require 'rnfse/string'
15
+
16
+ require 'rnfse/api'
17
+ require 'rnfse/api/abrasf_1_0'
18
+ require 'rnfse/api/iss_net_1_0'
19
+
20
+ require 'rnfse/xml_builder'
21
+ require 'rnfse/xml_builder/abrasf_1_0'
22
+ require 'rnfse/xml_builder/iss_net_1_0'
data/rnfse.gemspec ADDED
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'rnfse/version'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'rnfse'
10
+ s.version = Rnfse::VERSION
11
+ s.summary = %q{Biblioteca para a API de Nota Fiscal de Serviços
12
+ eletrônica (NFS-e) da ABRASF.}
13
+ s.description = %q{Biblioteca para integração com as várias implementações
14
+ municipais de Nota Fiscal de Serviços eletrônica (NFS-e) que utilizam uma
15
+ das versões ou variações dos padrões
16
+ [ABRASF](http://www.abrasf.org.br/paginas_multiplas_detalhes.php?cod_pagina=1).}
17
+
18
+ s.required_ruby_version = '>= 1.9.3'
19
+
20
+ s.licenses = ['MIT', 'GPL-3']
21
+
22
+ s.authors = ['Renan Mendes Carvalho']
23
+ s.email = ['aitherios@gmail.com']
24
+ s.homepage = 'https://github.com/aitherios/rnfse'
25
+
26
+ s.files = `git ls-files`.split($/)
27
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
28
+ s.require_paths = ['lib']
29
+ s.rubyforge_project = '[none]'
30
+
31
+ s.add_dependency 'json', '~> 1.0'
32
+ s.add_dependency 'json-schema', '~> 2.0'
33
+ s.add_dependency 'gyoku', '~> 1.0'
34
+ s.add_dependency 'nokogiri-xmlsec1', '~> 0.0.7'
35
+ s.add_dependency 'savon', '~> 2.0'
36
+
37
+ s.add_development_dependency 'bundler', '~> 1.3'
38
+ s.add_development_dependency 'rake', '~> 10.0'
39
+ s.add_development_dependency 'rdoc', '~> 4.0'
40
+ s.add_development_dependency 'gem-release', '~> 0.7.0'
41
+ s.add_development_dependency 'rspec', '~> 3.0.0'
42
+ s.add_development_dependency 'rspec-its', '~> 1.0.0'
43
+ s.add_development_dependency 'simplecov', '~> 0.7.0'
44
+ s.add_development_dependency 'codeclimate-test-reporter', '>= 0'
45
+ s.add_development_dependency 'equivalent-xml', '~> 0.4.0'
46
+ s.add_development_dependency 'wwtd', '~> 0.5.0'
47
+ s.add_development_dependency 'vcr', '~> 2.9'
48
+ s.add_development_dependency 'webmock', '~> 1.0'
49
+ s.add_development_dependency 'guard', '~> 2.6.0'
50
+ s.add_development_dependency 'guard-rspec', '~> 4.2.0'
51
+ s.add_development_dependency 'guard-bundler', '~> 2.0.0'
52
+ s.add_development_dependency 'foreman', '~> 0.74.0'
53
+ s.add_development_dependency 'pry', '~> 0.10'
54
+ if RUBY_VERSION.to_i < 2
55
+ s.add_development_dependency 'pry-debugger', '~> 0.2'
56
+ else
57
+ s.add_development_dependency 'pry-byebug', '~> 1.0'
58
+ end
59
+
60
+ end