caligrafo 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
- *.sw?
2
- .DS_Store
3
1
  coverage
4
2
  rdoc
5
3
  pkg
6
- test/*.txt
4
+ test/arquivo_gerado.txt
5
+ test/tmp.txt
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{caligrafo}
8
- s.version = "0.1.3"
8
+ s.version = "0.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Lucas de Castro"]
12
- s.date = %q{2009-11-03}
12
+ s.date = %q{2009-11-18}
13
13
  s.description = %q{DSL para geração de arquivos texto.}
14
14
  s.email = %q{castro.lucas@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,9 +25,15 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "caligrafo.gemspec",
27
27
  "lib/caligrafo.rb",
28
+ "lib/caligrafo/converter.rb",
29
+ "lib/caligrafo/descriptor.rb",
30
+ "lib/caligrafo/fixnum.rb",
31
+ "lib/caligrafo/reader.rb",
32
+ "lib/caligrafo/writer.rb",
28
33
  "test/caligrafo_test.rb",
34
+ "test/example.rb",
35
+ "test/example.txt",
29
36
  "test/formatador_test.rb",
30
- "test/leitura_test.rb",
31
37
  "test/test_helper.rb"
32
38
  ]
33
39
  s.homepage = %q{http://github.com/lucasdecastro/caligrafo}
@@ -39,7 +45,7 @@ Gem::Specification.new do |s|
39
45
  "test/test_helper.rb",
40
46
  "test/caligrafo_test.rb",
41
47
  "test/formatador_test.rb",
42
- "test/leitura_test.rb"
48
+ "test/example.rb"
43
49
  ]
44
50
 
45
51
  if s.respond_to? :specification_version then
@@ -1,460 +1,18 @@
1
- module Caligrafo
2
- def self.included(base)
3
- base.instance_eval do
4
- include InstanceMethods
5
- extend ClassMethods
6
- end
7
- end
8
-
9
- module InstanceMethods
10
- def criar_arquivo(nome_arquivo, &bloco)
11
- arquivo = Arquivo.new(nome_arquivo, bloco)
12
- arquivo.criar_arquivo
13
- nome_arquivo
14
- end
15
-
16
- def escrever_arquivo(nome, &bloco)
17
- estrutura = self.class.instance_variable_get "@arquivo"
18
-
19
- File.open(nome, 'w') do |file|
20
- file.extend ArquivoExtensao
21
- file.estrutura = estrutura
22
- file.linha = ''
23
- file.numero_linha = 1
24
- file.objeto = self
25
- file.bloco = bloco
26
-
27
- bloco.call file
28
- end
29
-
30
- nome
31
- end
32
-
33
- def ler_arquivo(nome, &bloco)
34
- estrutura = self.class.instance_variable_get "@arquivo"
35
- raise 'A estrutura nao foi definida' if estrutura.nil?
36
-
37
- File.open(nome, 'r') do |file|
38
- while linha = file.gets
39
- linha.extend LinhaArquivoExtensao
40
- linha.arquivo = estrutura
41
- linha.descobrir_secao
42
-
43
- bloco.call linha
44
- end
45
- end
46
- end
47
- end
48
-
49
- module ArquivoExtensao
50
- attr_accessor :objeto, :indice, :linha, :numero_linha, :bloco, :estrutura
51
-
52
- def secao(nome, &bloco)
53
- if self.objeto.respond_to? nome
54
- objetos = self.objeto.send nome
55
- objetos = [objetos] if objetos.nil? or !objetos.is_a?(Array)
56
- else
57
- objetos = [objeto]
58
- end
59
-
60
- objetos.each_with_index do |objeto, index|
61
- self.objeto = objeto
62
- self.indice = index
63
-
64
- bloco.call objeto
65
- nova_linha
66
- end
67
-
68
- self.objeto = self.bloco.binding.send :eval, "self"
69
- end
70
-
71
- def nova_linha
72
- self.linha = ''
73
- self.numero_linha += 1
74
- self.print "\n"
75
- end
76
-
77
- def imprimir(*args)
78
- campo = Campo.new(*args)
79
- valor_campo = campo.valor_para(objeto)
80
-
81
- posicao = campo.posicao
82
- if posicao
83
- valor_campo = valor_campo.rjust(posicao - self.linha.size + 1)
84
- end
85
-
86
- self.linha << valor_campo
87
- self.print valor_campo
88
- end
89
- end
90
-
91
- module LinhaArquivoExtensao
92
- attr_accessor :arquivo
93
-
94
- def secao
95
- if @secao
96
- @secao.nome
97
- end
98
- end
99
-
100
- def secao?(nome_secao)
101
- @arquivo.secoes.find {|s| s.nome == nome_secao }
102
- end
103
-
104
- def ler(nome_campo)
105
- if @secao
106
- campo = @secao.campos.find {|c| c.nome == nome_campo }
107
- campo.ler(self) if campo
108
- end
109
- end
110
-
111
- def ler_campos
112
- if @secao
113
- hash = {}
114
- @secao.campos.each {|c| hash[c.nome] = c.ler(self) }
115
- hash
116
- end
117
- end
118
-
119
- def descobrir_secao
120
- @secao = @arquivo.secoes.find {|s| s.dessa_linha?(self) }
121
- end
122
- end
123
-
124
- module Helpers
125
- def executar(bloco)
126
- self.class.send :define_method, :executar_bloco, &bloco
127
- self.executar_bloco
128
- end
129
-
130
- def extrair_opcoes(args)
131
- args.last.is_a?(Hash) ? args.pop : {}
132
- end
133
- end
134
-
135
- module ClassMethods
136
-
137
- def arquivo(&bloco)
138
- @arquivo = Arquivo.new
139
- @arquivo.executar bloco
140
- end
141
-
142
- class Arquivo
143
- include Caligrafo::Helpers
144
-
145
- attr_accessor :bloco
146
-
147
- def secoes
148
- @secoes ||= []
149
- end
150
-
151
- def secao(nome, &bloco)
152
- secao = Secao.new(nome, bloco)
153
- secoes << secao
154
- secao.executar bloco
155
- end
156
- end
157
-
158
- class Secao
159
- include Caligrafo::Helpers
160
-
161
- attr_accessor :nome, :bloco
162
-
163
- def initialize(nome, bloco)
164
- @nome = nome
165
- @bloco = bloco
166
- end
167
-
168
- def campos
169
- @campos ||= []
170
- end
171
-
172
- def campo(nome, *opcoes)
173
- campo = Campo.new(self, nome, *opcoes)
174
- self.campos << campo
175
- campo
176
- end
177
-
178
- def dessa_linha?(linha)
179
- linha =~ /^#{campos.first.valor_padrao}/
180
- end
181
- end
182
-
183
- class Campo
184
- include Caligrafo::Helpers
185
-
186
- attr_accessor :secao, :nome, :inicio, :fim, :formatador, :valor_padrao
187
-
188
- def initialize(secao, nome, *args)
189
- self.secao = secao
190
- self.nome = nome
191
-
192
- opcoes = extrair_opcoes(args)
193
- self.inicio = opcoes.delete(:inicio)
194
- self.fim = opcoes.delete(:fim)
195
- self.formatador = Formatador.pesquisar_por_nome(opcoes.delete(:formato))
196
-
197
- if args.first
198
- self.valor_padrao = args.first
199
- opcoes[:tamanho] = self.valor_padrao.to_s.size
200
- end
201
-
202
- if opcoes.key? :posicao
203
- posicao = opcoes.delete(:posicao)
204
- self.inicio = posicao.first
205
- self.fim = posicao.last
206
- else
207
- ajustar_inicio_e_fim(opcoes.delete(:tamanho))
208
- end
209
- end
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
210
2
 
211
- def tamanho
212
- if self.fim and self.inicio
213
- self.fim - self.inicio + 1 # Inclui o ultimo elemento
214
- else
215
- nil
216
- end
217
- end
3
+ require 'caligrafo/descriptor'
4
+ require 'caligrafo/writer'
5
+ require 'caligrafo/reader'
6
+ require 'caligrafo/fixnum'
218
7
 
219
- def ler(linha)
220
- fim = self.fim || 0
221
- linha[(self.inicio - 1)..(fim - 1)]
222
- end
223
-
224
- private
225
- def ajustar_inicio_e_fim(tamanho)
226
- self.inicio ||= calcular_inicio
227
- self.fim ||= self.inicio + tamanho - 1 if tamanho
228
- end
229
-
230
- def calcular_inicio
231
- campo_anterior = self.secao.campos.last
232
- if campo_anterior
233
- ultima_posicao = campo_anterior.fim
234
- ultima_posicao + 1
235
- else
236
- 1
237
- end
238
- end
239
- end
240
- end
241
-
242
- module Formatador
243
- def self.formatadores
244
- @@formatadores ||= {}
245
- end
246
-
247
- def self.registrar(nome, formatador)
248
- self.formatadores[nome] = formatador.new
249
- end
250
-
251
- def self.pesquisar_por_nome(nome)
252
- self.formatadores[nome]
253
- end
254
-
255
- def self.pesquisar_por_nome!(nome)
256
- self.pesquisar_por_nome(nome) or raise FormatadorNaoEncontrado, "O formatador #{nome.inspect} nao foi registrado!"
257
- end
258
-
259
- def self.pesquisar_por_tipo(tipo)
260
- formatador = self.formatadores.values.find { |f| f.tipos.include? tipo }
261
- formatador ||= self.formatadores[:default]
262
- end
263
-
264
- class FormatadorNaoEncontrado < Exception; end
265
-
266
- class Base
267
- attr_reader :tipos, :alinhamento, :preenchimento
268
-
269
- def initialize
270
- @tipos = []
271
- @alinhamento = :esquerda
272
- @preenchimento = ' '
273
- end
274
-
275
- def formatar(valor, opcoes = {})
276
- valor.to_s
277
- end
278
-
279
- def preencher(string, tamanho)
280
- if self.alinhamento == :direita
281
- string = string.rjust tamanho, self.preenchimento
282
- else
283
- string = string.ljust tamanho, self.preenchimento
284
- end
285
-
286
- string = string[0..(tamanho - 1)] if string.size > tamanho
287
- string
288
- end
289
- end
290
-
291
- class Data < Base
292
- def tipos
293
- [Date]
294
- end
295
-
296
- def formatar(valor, opcoes={})
297
- valor.strftime('%Y%m%d')
298
- end
299
- end
300
-
301
- class Numerico < Base
302
- def initialize
303
- @tipos = [Fixnum]
304
- end
305
-
306
- def alinhamento
307
- :direita
308
- end
309
-
310
- def preenchimento
311
- '0'
312
- end
313
- end
314
-
315
- class Decimal < Numerico
316
- def initialize
317
- @tipos = [Float]
318
- end
319
-
320
- def formatar(valor, opcoes = {})
321
- ('%.2f' % valor).gsub('.','')
322
- end
323
- end
324
-
325
- self.registrar :default, Base
326
- self.registrar :alpha, Base
327
- self.registrar :numerico, Numerico
328
- self.registrar :decimal, Decimal
329
- self.registrar :data, Caligrafo::Formatador::Data
330
- end
331
-
332
- class Arquivo
333
- attr_reader :nome, :bloco
334
- attr_accessor :objeto, :indice, :linha, :numero_linha, :file
335
-
336
- def initialize(nome, bloco)
337
- @nome = nome
338
- @bloco = bloco
339
- @linha = ''
340
- @numero_linha = 1
341
- end
342
-
343
- def criar_arquivo
344
- # Se eu simplesmente chamasse o bloco, os método de Arquivo
345
- # não estariam disponíveis. ;)
346
- self.class.send :define_method, :executar_bloco, &bloco
347
-
348
- self.objeto = bloco.binding.send :eval, "self"
349
-
350
- File.open(nome, 'w') do |file|
351
- self.file = file
352
- executar_bloco
353
- end
354
-
355
- nome
356
- end
357
-
358
- def secao(nome, &bloco)
359
- if self.objeto.respond_to? nome
360
- objetos = self.objeto.send nome
361
- objetos = [objetos] if objetos.nil? or !objetos.is_a?(Array)
362
- else
363
- objetos = [objeto]
364
- end
365
-
366
- objetos.each_with_index do |objeto, index|
367
- self.objeto = objeto
368
- self.indice = index
369
- bloco.call objeto
370
- nova_linha
371
- end
372
-
373
- self.objeto = self.bloco.binding.send :eval, "self"
374
- end
375
-
376
- def nova_linha
377
- self.linha = ''
378
- self.numero_linha += 1
379
- self.file.print "\n"
380
- end
381
-
382
- def imprimir(*args)
383
- campo = Campo.new(*args)
384
- valor_campo = campo.valor_para(objeto)
385
-
386
- posicao = campo.posicao
387
- if posicao
388
- valor_campo = valor_campo.rjust(posicao - self.linha.size + 1)
389
- end
390
-
391
- self.linha << valor_campo
392
- self.file.print valor_campo
393
- end
394
- end
395
-
396
- # campo :nome
397
- # campo :profisao, 'Programador'
398
- # campo :idade, 46, :posicao => 12
399
- # campo :tentativas, :alinhamento => :esquerda, :tamanho => 10
400
- # campo :salario, :formato => :decimal
401
- # campo 'FIM'
402
- class Campo
403
- attr_accessor :nome, :valor, :posicao, :formato, :tamanho, :opcoes_para_formatador
404
-
405
- def initialize(*args)
406
- opcoes = (args.last.is_a?(Hash) ? args.pop : {})
407
- @formato = opcoes.delete(:formato)
408
- @posicao = opcoes.delete(:posicao)
409
- @tamanho = opcoes.delete(:tamanho)
410
- @opcoes_para_formatador = opcoes
411
-
412
- if args.first.is_a? Symbol
413
- @nome = args.first
414
- @valor = args[1]
415
- @chamar_metodo = true if args.size == 1
416
- else
417
- @valor = args.first
418
- end
419
- end
420
-
421
- def valor_para(objeto)
422
- valor = if chamar_metodo?
423
- begin
424
- objeto.send(self.nome)
425
- rescue Exception => e
426
- raise "Erro ao chamar #{self.nome.inspect} em #{objeto}: #{e.message}"
427
- end
428
- else
429
- self.valor
430
- end
431
-
432
- formatar(valor)
433
- end
434
-
435
- private
436
- def chamar_metodo?
437
- @chamar_metodo
438
- end
439
- def formatar(valor)
440
- if self.formato
441
- formatador = Formatador.pesquisar_por_nome self.formato
442
- else
443
- formatador = Formatador.pesquisar_por_tipo valor.class
444
- end
445
-
446
- string = formatador.formatar(valor, self.opcoes_para_formatador)
447
- string = formatador.preencher(string, self.tamanho) if self.tamanho
448
- string
449
- end
450
- end
451
- end
8
+ module Caligrafo
9
+ include Writer
10
+ include Reader
452
11
 
453
- # TODO criar arquivo de extensoes.
454
- class ::Fixnum
455
- def espacos
456
- ' ' * self
12
+ def self.included(base)
13
+ base.extend Descriptor
14
+ base.extend Reader
457
15
  end
458
- alias espaco espacos
459
16
  end
460
17
 
18
+ Fixnum.send :include, Caligrafo::Fixnum
@@ -0,0 +1,105 @@
1
+ module Caligrafo
2
+ module Converter
3
+ def self.formatadores
4
+ @@formatadores ||= {}
5
+ end
6
+
7
+ def self.registrar(nome, formatador)
8
+ self.formatadores[nome] = formatador.new
9
+ end
10
+
11
+ def self.pesquisar_por_nome(nome)
12
+ self.formatadores[nome]
13
+ end
14
+
15
+ def self.pesquisar_por_nome!(nome)
16
+ resultado = self.pesquisar_por_nome(nome)
17
+ raise ConverterNotFound, "O formatador #{nome.inspect} nao foi registrado!" unless resultado
18
+ resultado
19
+ end
20
+
21
+ def self.pesquisar_por_tipo(tipo)
22
+ formatador = self.formatadores.values.find { |f| f.tipos.include? tipo }
23
+ formatador ||= self.formatadores[:default]
24
+ end
25
+
26
+ class ConverterNotFound < Exception; end
27
+
28
+ class Base
29
+ attr_reader :tipos, :alinhamento, :preenchimento
30
+
31
+ def initialize
32
+ @tipos = []
33
+ @alinhamento = :esquerda
34
+ @preenchimento = ' '
35
+ end
36
+
37
+ def value_to_string(valor)
38
+ valor.to_s
39
+ end
40
+
41
+ def string_to_value(string)
42
+ string.strip
43
+ end
44
+
45
+ def preencher(string, tamanho)
46
+ if self.alinhamento == :direita
47
+ string = string.rjust tamanho, self.preenchimento
48
+ else
49
+ string = string.ljust tamanho, self.preenchimento
50
+ end
51
+
52
+ string = string[0..(tamanho - 1)] if string.size > tamanho
53
+ string
54
+ end
55
+ end
56
+
57
+ class Data < Base
58
+ def tipos
59
+ [Date]
60
+ end
61
+
62
+ def value_to_string(valor)
63
+ valor.strftime('%Y%m%d')
64
+ end
65
+
66
+ def string_to_value(string)
67
+ Date.strptime string, '%Y%m%d'
68
+ end
69
+ end
70
+
71
+ class Numerico < Base
72
+ def initialize
73
+ @tipos = [Fixnum]
74
+ end
75
+
76
+ def string_to_value(string)
77
+ string.to_i
78
+ end
79
+
80
+ def alinhamento
81
+ :direita
82
+ end
83
+
84
+ def preenchimento
85
+ '0'
86
+ end
87
+ end
88
+
89
+ class Decimal < Numerico
90
+ def initialize
91
+ @tipos = [Float]
92
+ end
93
+
94
+ def value_to_string(valor)
95
+ ('%.2f' % valor).gsub('.','')
96
+ end
97
+ end
98
+
99
+ self.registrar :default, Base
100
+ self.registrar :alpha, Base
101
+ self.registrar :numerico, Numerico
102
+ self.registrar :decimal, Decimal
103
+ self.registrar :data, Data
104
+ end
105
+ end
@@ -0,0 +1,176 @@
1
+ module Caligrafo
2
+ module Descriptor
3
+ def arquivo(&bloco)
4
+ @@arquivo = Arquivo.new
5
+ @@arquivo.executar bloco
6
+ end
7
+
8
+ def estrutura
9
+ @@arquivo
10
+ end
11
+
12
+ module Helpers
13
+ def executar(bloco)
14
+ self.class.send :define_method, :executar_bloco, &bloco
15
+ self.executar_bloco
16
+ end
17
+
18
+ def extrair_opcoes(args)
19
+ args.last.is_a?(Hash) ? args.pop : {}
20
+ end
21
+ end
22
+
23
+ class Arquivo
24
+ include Helpers
25
+
26
+ attr_accessor :bloco
27
+
28
+ def secoes
29
+ @secoes ||= []
30
+ end
31
+
32
+ def secao(nome, &bloco)
33
+ secao = Secao.new(nome, bloco)
34
+ secoes << secao
35
+ secao.executar bloco
36
+ end
37
+ end
38
+
39
+ class Secao
40
+ include Helpers
41
+
42
+ attr_accessor :nome, :bloco
43
+
44
+ def initialize(nome, bloco)
45
+ @nome = nome
46
+ @bloco = bloco
47
+ end
48
+
49
+ def campos
50
+ @campos ||= []
51
+ end
52
+
53
+ def campo(nome, *opcoes)
54
+ campo = Campo.new(self, nome, *opcoes)
55
+ self.campos << campo
56
+ campo
57
+ end
58
+
59
+ def dessa_linha?(linha)
60
+ linha =~ /^#{campos.first.valor_padrao}/
61
+ end
62
+ end
63
+
64
+ class Campo
65
+ include Helpers
66
+
67
+ attr_accessor :secao, :nome, :inicio, :fim, :formatador, :valor_padrao
68
+
69
+ def initialize(secao, nome, *args)
70
+ self.secao = secao
71
+ self.nome = nome
72
+ configura(args)
73
+ end
74
+
75
+ def configura(args)
76
+ opcoes = extrair_opcoes(args)
77
+ self.inicio = opcoes.delete(:inicio)
78
+ self.fim = opcoes.delete(:fim)
79
+ self.formatador = Converter.pesquisar_por_nome(opcoes.delete(:formato))
80
+
81
+ valor_padrao = args.first
82
+ if valor_padrao
83
+ self.valor_padrao = valor_padrao
84
+ opcoes[:tamanho] = self.valor_padrao.to_s.size
85
+ else
86
+ @chamar_metodo = true
87
+ end
88
+
89
+ if opcoes.key? :posicao
90
+ posicao = opcoes.delete(:posicao)
91
+ case posicao
92
+ when Range:
93
+ self.inicio = posicao.first
94
+ self.fim = posicao.last
95
+ when Fixnum:
96
+ self.inicio = calcular_inicio - posicao
97
+ self.fim = self.inicio + posicao
98
+ else
99
+ raise ArgumentError, 'use um Range ou Fixnum para definir a posicao do campo.'
100
+ end
101
+ else
102
+ ajustar_inicio_e_fim(opcoes.delete(:tamanho))
103
+ end
104
+ end
105
+
106
+ def tamanho
107
+ if self.fim and self.inicio
108
+ self.fim - self.inicio + 1 # Inclui o ultimo elemento
109
+ else
110
+ nil
111
+ end
112
+ end
113
+
114
+ def ler(linha)
115
+ fim = self.fim || 0
116
+ substring = linha[(self.inicio - 1)..(fim - 1)]
117
+
118
+ if formatador
119
+ formatador.string_to_value substring
120
+ else
121
+ Converter.formatadores[:default].string_to_value substring
122
+ end
123
+ end
124
+
125
+ def guarda_valor_para(objeto, valor)
126
+ @valor_guardado = formatar(valor)
127
+ end
128
+
129
+ def valor_guardado
130
+ @valor_guardado
131
+ end
132
+
133
+ def valor_para(objeto)
134
+ valor = if objeto.respond_to? self.nome
135
+ objeto.send(self.nome)
136
+ else
137
+ self.valor_padrao
138
+ end
139
+
140
+ formatar(valor)
141
+ rescue => e
142
+ raise "Erro ao preencher valor para #{objeto.inspect} no campo #{self.inspect}: #{e.message}"
143
+ end
144
+
145
+ private
146
+
147
+ def chamar_metodo?
148
+ @chamar_metodo
149
+ end
150
+
151
+ def formatar(valor)
152
+ formatador = self.formatador
153
+ formatador ||= Converter.pesquisar_por_tipo valor.class
154
+
155
+ string = formatador.value_to_string(valor)
156
+ string = formatador.preencher(string, self.tamanho) if self.tamanho
157
+ string
158
+ end
159
+
160
+ def ajustar_inicio_e_fim(tamanho)
161
+ self.inicio ||= calcular_inicio
162
+ self.fim ||= self.inicio + tamanho - 1 if tamanho
163
+ end
164
+
165
+ def calcular_inicio
166
+ campo_anterior = self.secao.campos.last
167
+ if campo_anterior
168
+ ultima_posicao = campo_anterior.fim
169
+ (ultima_posicao ? ultima_posicao + 1 : 1)
170
+ else
171
+ 1
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,8 @@
1
+ module Caligrafo
2
+ module Fixnum
3
+ def espacos
4
+ ' ' * self
5
+ end
6
+ alias espaco espacos
7
+ end
8
+ end
@@ -0,0 +1,52 @@
1
+ module Caligrafo
2
+ module Reader
3
+ def ler_arquivo(nome, &bloco)
4
+ estrutura = (self.is_a?(Class) ? self.estrutura : self.class.estrutura)
5
+ raise 'A estrutura nao foi definida' unless estrutura
6
+
7
+ File.open(nome, 'r') do |file|
8
+ while linha = file.gets
9
+ linha.extend LineExtension
10
+ linha.arquivo = estrutura
11
+ linha.descobrir_secao
12
+ linha.numero = file.lineno
13
+
14
+ bloco.call linha
15
+ end
16
+ end
17
+ end
18
+
19
+ module LineExtension
20
+ attr_accessor :arquivo, :numero
21
+
22
+ def secao
23
+ if @secao
24
+ @secao.nome
25
+ end
26
+ end
27
+
28
+ def secao?(nome_secao)
29
+ @arquivo.secoes.find {|s| s.nome == nome_secao }
30
+ end
31
+
32
+ def ler(nome_campo)
33
+ if @secao
34
+ campo = @secao.campos.find {|c| c.nome == nome_campo }
35
+ campo.ler(self) if campo
36
+ end
37
+ end
38
+
39
+ def ler_campos
40
+ if @secao
41
+ hash = {}
42
+ @secao.campos.each {|c| hash[c.nome] = c.ler(self) }
43
+ hash
44
+ end
45
+ end
46
+
47
+ def descobrir_secao
48
+ @secao = @arquivo.secoes.find {|s| s.dessa_linha?(self) }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,65 @@
1
+ require 'caligrafo/converter'
2
+
3
+ module Caligrafo
4
+ module Writer
5
+ def escrever_arquivo(nome, &bloco)
6
+ raise 'A estrutura nao foi definida' unless self.class.estrutura
7
+
8
+ File.open(nome, 'w') do |file|
9
+ file.extend FileExtension
10
+ file.estrutura = self.class.estrutura
11
+ file.linha = ''
12
+ file.numero_linha = 1
13
+ file.objeto = self
14
+ file.bloco = bloco
15
+
16
+ bloco.call file
17
+ end
18
+
19
+ nome
20
+ end
21
+
22
+ module FileExtension
23
+ attr_accessor :objeto, :indice, :linha, :numero_linha, :bloco, :estrutura, :secao_corrente
24
+
25
+ def secao(nome, &bloco)
26
+ self.secao_corrente = self.estrutura.secoes.find {|secao| secao.nome == nome }
27
+
28
+ if self.objeto.respond_to? nome
29
+ objetos = self.objeto.send nome
30
+ objetos = [objetos] if objetos.nil? or !objetos.is_a?(Array)
31
+ else
32
+ objetos = [objeto]
33
+ end
34
+
35
+ objetos.each_with_index do |objeto, index|
36
+ self.objeto = objeto
37
+ self.indice = index
38
+
39
+ bloco.call objeto
40
+ if self.estrutura
41
+ for campo in self.secao_corrente.campos
42
+ self.print(campo.valor_guardado || campo.valor_para(self.objeto))
43
+ end
44
+ end
45
+
46
+ nova_linha
47
+ end
48
+
49
+ self.objeto = self.bloco.binding.send :eval, "self"
50
+ end
51
+
52
+ def nova_linha
53
+ self.linha = ''
54
+ self.numero_linha += 1
55
+ self.print "\n"
56
+ end
57
+
58
+ # Sobrescreve a definição do arquivo.
59
+ def imprimir(nome_campo, valor)
60
+ campo = self.secao_corrente.campos.find {|campo_pre_definido| campo_pre_definido.nome == nome_campo}
61
+ campo.guarda_valor_para(self.objeto, valor)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,65 +1,85 @@
1
1
  require 'test_helper'
2
- require 'caligrafo'
3
- require 'ostruct'
2
+ require 'example'
4
3
 
4
+ class CaligrafoTest < Test::Unit::TestCase
5
+ def setup
6
+ @portifolio = Portifolio.new :nome => 'Lucas da Silva',
7
+ :idade => 25,
8
+ :salario => 90_000.5,
9
+ :telefones => ['558622223333', '558699991234'],
10
+ :sites => ['Google.com', 'Blip.tv', 'SlideShare.net']
11
+ end
5
12
 
6
- class Portifolio < OpenStruct
7
- include Caligrafo
13
+ def test_writing
14
+ @portifolio.gerar_arquivo 'test/arquivo_gerado.txt'
15
+ assert_file_content 'test/arquivo_gerado.txt', <<-EOF
16
+ 01Lucas da Silva 0259000050 1
17
+ 02Fone#1: 55 86 2222-3333 2
18
+ 02Fone#2: 55 86 9999-1234 3
19
+ 03google.com 4
20
+ 03blip.tv 5
21
+ 03slideshare.net 6
22
+ 04FIM 7
23
+ EOF
24
+ end
8
25
 
9
- def gerar_arquivo(nome_arquivo)
10
- escrever_arquivo nome_arquivo do |f|
11
- f.secao :cabecalho do
12
- f.imprimir :nome, :tamanho => 50 # Textos são alinhados à esquerda.
13
- f.imprimir :idade, :tamanho => 3 # Números são alinhados à direita com zeros à esquerda.
14
- f.imprimir :salario # Decimais possuem duas casas decimais.
15
- f.imprimir 5.espacos # Quando o 1º parâmetro não for um símbolo ele será o conteúdo.
16
- f.imprimir f.numero_linha, :posicao => 100 # 'numero_linha' é um método que guarda a linha corrente do arquivo.
17
- end
26
+ def test_numero_linha
27
+ counter = 1
28
+ @portifolio.ler_arquivo 'test/example.txt' do |linha|
29
+ assert counter, linha.numero
30
+ counter += 1
31
+ end
32
+ assert 7, counter
33
+ end
18
34
 
19
- f.secao :telefones do |telefone| # telefones é um método. Escreve uma linha pora cada objeto retornado.
20
- f.imprimir :descricao, "Fone##{f.indice + 1}: " # Valor fixo sendo usado como 2º parâmetro.
21
- # O 1º fica sendo usado apenas para descrição.
22
- # 'indice' é um método que guarda o indice do elemento no array.
23
- f.imprimir telefone, :formato => :fone # Usando um formatador personalizado.
24
- f.imprimir f.numero_linha, :posicao => 100 # posicao é usado para pular para uma coluna. Até lá tudo será vazio (' ').
25
- end
35
+ def test_ler_da_classe
36
+ Portifolio.ler_arquivo 'test/example.txt' do |linha|
37
+ assert true
38
+ break
39
+ end
40
+ end
26
41
 
27
- f.secao :sites do |site|
28
- f.imprimir :downcase # Podemos chamar o método do item nas seções.
29
- f.imprimir :numero_linha, f.numero_linha, :posicao => 100
30
- end
42
+ def test_secao
43
+ @portifolio.ler_arquivo 'test/example.txt' do |linha|
44
+ nome_secao = case linha.numero
45
+ when 1 then :cabecalho
46
+ when 2..3 then :telefones
47
+ when 4..6 then :sites
48
+ when 7 then :rodape
49
+ end
50
+ assert_equal nome_secao, linha.secao, "secao nao eh #{nome_secao.inspect}"
51
+ end
52
+ end
31
53
 
32
- f.secao :rodape do
33
- f.imprimir 'FIM' # Uma nova linha é criada sempre que saimos ou entramos numa seção.
34
- f.imprimir f.numero_linha, :posicao => 100 # Como não definimos o tamanho, ficará alinhado à esquerda, mesmo sendo número.
35
- end
54
+ def test_secao?
55
+ @portifolio.ler_arquivo 'test/example.txt' do |linha|
56
+ assert linha.secao?(linha.secao)
36
57
  end
37
58
  end
38
- end
39
59
 
40
- class Telefone < Caligrafo::Formatador::Base
41
- def formatar(valor, opcoes={})
42
- valor.gsub(/(\d\d)(\d\d)(\d\d\d\d)(\d\d\d\d)/,'\1 \2 \3-\4') if valor
60
+ def test_ler_campo
61
+ @portifolio.ler_arquivo 'test/example.txt' do |linha|
62
+ case linha.secao
63
+ when :cabecalho
64
+ assert_equal '01', linha.ler(:tipo)
65
+ assert_equal 'Lucas da Silva', linha.ler(:nome)
66
+ assert_equal 25, linha.ler(:idade)
67
+ end
68
+ end
43
69
  end
44
- end
45
- Caligrafo::Formatador.registrar :fone, Telefone
46
70
 
47
- class CaligrafoTest < Test::Unit::TestCase
48
- def test_gerar_arquivo
49
- pessoa = Portifolio.new :nome => 'Lucas da Silva',
50
- :idade => 25,
51
- :salario => 90_000.5,
52
- :telefones => ['558622223333', '558699991234'],
53
- :sites => ['Google.com', 'Blip.tv', 'SlideShare.net']
54
- pessoa.gerar_arquivo 'test/arquivo_gerado.txt'
55
- assert_file_content 'test/arquivo_gerado.txt', <<-EOF
56
- Lucas da Silva 0259000050 1
57
- Fone#1: 55 86 2222-3333 2
58
- Fone#2: 55 86 9999-1234 3
59
- google.com 4
60
- blip.tv 5
61
- slideshare.net 6
62
- FIM 7
63
- EOF
71
+ def test_description
72
+ arquivo = Portifolio.estrutura
73
+ assert arquivo
74
+
75
+ cabecalho = arquivo.secoes.first
76
+ assert_equal :cabecalho, cabecalho.nome
77
+
78
+ registros = arquivo.secoes.last
79
+ assert_equal :rodape, registros.nome
80
+
81
+ campos = cabecalho.campos
82
+ assert_equal 6, campos.size
64
83
  end
84
+
65
85
  end
@@ -0,0 +1,62 @@
1
+ require 'caligrafo'
2
+ require 'ostruct'
3
+
4
+ class Telefone < Caligrafo::Converter::Base
5
+ def value_to_string(valor)
6
+ valor.to_s.gsub(/(\d\d)(\d\d)(\d\d\d\d)(\d\d\d\d)/,'\1 \2 \3-\4')
7
+ end
8
+ end
9
+
10
+ Caligrafo::Converter.registrar :fone, Telefone
11
+
12
+ class Portifolio < OpenStruct
13
+ include Caligrafo
14
+
15
+ arquivo do
16
+ secao :cabecalho do
17
+ campo :tipo, '01'
18
+ campo :nome, :tamanho => 50
19
+ campo :idade, :tamanho => 3, :formato => :numerico
20
+ campo :salario, :tamanho => 7
21
+ campo :vazio, 7.espacos
22
+ campo :linha
23
+ end
24
+ secao :telefones do
25
+ campo :tipo, '02'
26
+ campo :descricao, :tamanho => 8
27
+ campo :to_s, :tamanho => 59, :formato => :fone
28
+ campo :linha
29
+ end
30
+ secao :sites do
31
+ campo :tipo, '03'
32
+ campo :downcase, :tamanho => 67
33
+ campo :linha
34
+ end
35
+ secao :rodape do
36
+ campo :tipo, '04'
37
+ campo :fim, 'FIM'
38
+ campo :vazio, 64.espacos
39
+ campo :linha
40
+ end
41
+ end
42
+
43
+ def gerar_arquivo(nome_arquivo)
44
+ escrever_arquivo nome_arquivo do |f|
45
+ f.secao :cabecalho do
46
+ f.imprimir :linha, f.numero_linha
47
+ end
48
+ f.secao :telefones do
49
+ f.imprimir :descricao, "Fone##{f.indice + 1}: "
50
+ f.imprimir :linha, f.numero_linha
51
+ end
52
+ f.secao :sites do
53
+ f.imprimir :linha, f.numero_linha
54
+ end
55
+ f.secao :rodape do
56
+ f.imprimir :linha, f.numero_linha
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+
@@ -0,0 +1,7 @@
1
+ 01Lucas da Silva 0259000050 1
2
+ 02Fone#1: 55 86 2222-3333 2
3
+ 02Fone#2: 55 86 9999-1234 3
4
+ 03google.com 4
5
+ 03blip.tv 5
6
+ 03slideshare.net 6
7
+ 04FIM 7
@@ -1,12 +1,11 @@
1
1
  require 'test_helper'
2
2
  require 'caligrafo'
3
- require 'ostruct'
4
3
 
5
4
 
6
5
  class FormatadorTest < Test::Unit::TestCase
7
6
 
8
7
  def test_formatador_default
9
- test_formatador Caligrafo::Formatador::Base, 12, 10, '12 '
8
+ test_formatador Caligrafo::Converter::Base, 12, 10, '12 '
10
9
  end
11
10
 
12
11
  def test_formatador_personalizado
@@ -14,12 +13,12 @@ class FormatadorTest < Test::Unit::TestCase
14
13
  end
15
14
 
16
15
  def test_pesquisar_formatador_inexistente
17
- assert_raise Caligrafo::Formatador::FormatadorNaoEncontrado do
18
- Caligrafo::Formatador.pesquisar_por_nome! :bolinha
16
+ assert_raise Caligrafo::Converter::ConverterNotFound do
17
+ Caligrafo::Converter.pesquisar_por_nome! :bolinha
19
18
  end
20
19
 
21
20
  assert_nothing_raised do
22
- Caligrafo::Formatador.pesquisar_por_nome! :numerico
21
+ Caligrafo::Converter.pesquisar_por_nome! :numerico
23
22
  end
24
23
  end
25
24
 
@@ -27,7 +26,7 @@ class FormatadorTest < Test::Unit::TestCase
27
26
  def test_formatador(formatador, valor_original, tamanho, valor_esperado)
28
27
  f = formatador.new
29
28
 
30
- valor_formatado = f.formatar valor_original
29
+ valor_formatado = f.value_to_string valor_original
31
30
  valor_preenchido = f.preencher valor_formatado, tamanho
32
31
  assert_equal valor_esperado, valor_preenchido
33
32
  end
@@ -28,8 +28,13 @@ class Test::Unit::TestCase
28
28
  begin
29
29
  assert_equal line, lines_of_given_text[index]
30
30
  rescue Test::Unit::AssertionFailedError => e
31
- column = Diff::LCS.diff(line, lines_of_given_text[index]).first.first.position + 1
32
- raise Test::Unit::AssertionFailedError, "Line #{index + 1} dont match on column #{column}:\n#{e.message}"
31
+ given = lines_of_given_text[index]
32
+ if given
33
+ column = Diff::LCS.diff(line, lines_of_given_text[index]).first.first.position + 1
34
+ raise Test::Unit::AssertionFailedError, "Line #{index + 1} dont match on column #{column}:\n#{e.message}"
35
+ else
36
+ raise Test::Unit::AssertionFailedError, "Line #{index + 1} does not exist."
37
+ end
33
38
  end
34
39
  if content.to_a.size < given.read.to_a.size
35
40
  assert_equal content, given.read
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caligrafo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas de Castro
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-03 00:00:00 -03:00
12
+ date: 2009-11-18 00:00:00 -03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -31,9 +31,15 @@ files:
31
31
  - VERSION
32
32
  - caligrafo.gemspec
33
33
  - lib/caligrafo.rb
34
+ - lib/caligrafo/converter.rb
35
+ - lib/caligrafo/descriptor.rb
36
+ - lib/caligrafo/fixnum.rb
37
+ - lib/caligrafo/reader.rb
38
+ - lib/caligrafo/writer.rb
34
39
  - test/caligrafo_test.rb
40
+ - test/example.rb
41
+ - test/example.txt
35
42
  - test/formatador_test.rb
36
- - test/leitura_test.rb
37
43
  - test/test_helper.rb
38
44
  has_rdoc: true
39
45
  homepage: http://github.com/lucasdecastro/caligrafo
@@ -67,4 +73,4 @@ test_files:
67
73
  - test/test_helper.rb
68
74
  - test/caligrafo_test.rb
69
75
  - test/formatador_test.rb
70
- - test/leitura_test.rb
76
+ - test/example.rb
@@ -1,82 +0,0 @@
1
- require 'test_helper'
2
- require 'caligrafo'
3
-
4
-
5
- class LeituraTest < Test::Unit::TestCase
6
-
7
- class Exemplo
8
- include Caligrafo
9
-
10
- attr_accessor :posicao, :nome, :situacao
11
-
12
- arquivo do
13
- secao :cabecalho do
14
- campo :fixo, '01'
15
- campo :com_tamanho, :tamanho => 5
16
- campo :com_fim, :fim => 10
17
- campo :com_range, :posicao => 11..15
18
- campo :com_inicio, :inicio => 20, :formato => :decimal
19
- end
20
-
21
- secao :corpo do
22
- campo :vazio
23
- end
24
- end
25
-
26
- def smile
27
- ':)'
28
- end
29
-
30
- def ler(nome_arquivo)
31
- ler_arquivo nome_arquivo do |linha|
32
- if linha.secao? :cabecalho
33
- self.posicao = linha.ler(:fixo)
34
- self.nome = linha.ler_campos[:com_tamanho]
35
- end
36
- end
37
- end
38
- end
39
-
40
- def test_ler_arquivo
41
- arquivo = 'test/tmp.txt'
42
- File.open(arquivo, 'w') do |file|
43
- file.puts <<-EOF
44
- 0100005:) 150
45
- EOF
46
- end
47
-
48
- exemplo = Exemplo.new
49
- exemplo.ler(arquivo)
50
- assert_equal '01', exemplo.posicao
51
- assert_equal '00005', exemplo.nome
52
- end
53
-
54
- def test_dsl_com_informacoes_do_arquivo
55
- arquivo = Exemplo.instance_variable_get "@arquivo"
56
- assert arquivo
57
-
58
- cabecalho = arquivo.secoes.first
59
- assert_equal :cabecalho, cabecalho.nome
60
-
61
- registros = arquivo.secoes.last
62
- assert_equal :corpo, registros.nome
63
-
64
- campos = cabecalho.campos
65
- assert_equal 5, campos.size
66
-
67
- test_campo campos[0], :nome => :fixo, :inicio => 1, :fim => 2, :tamanho => 2, :valor_padrao => '01'
68
- test_campo campos[1], :nome => :com_tamanho, :inicio => 3, :fim => 7, :tamanho => 5
69
- test_campo campos[2], :nome => :com_fim, :inicio => 8, :fim => 10, :tamanho => 3
70
- test_campo campos[3], :nome => :com_range, :inicio => 11, :fim => 15, :tamanho => 5
71
- test_campo campos[4], :nome => :com_inicio, :inicio => 20, :fim => nil, :tamanho => nil
72
-
73
- assert_equal Caligrafo::Formatador::Decimal, campos[4].formatador.class
74
- end
75
-
76
- private
77
- def test_campo(campo, comparacoes = {})
78
- for campo_do_campo, valor_esperado in comparacoes
79
- assert_equal valor_esperado, campo.send(campo_do_campo), "campo #{campo.nome} nao bateu no #{campo_do_campo}"
80
- end
81
- end
82
- end