zapata 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/CONTRIBUTING.md +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +22 -0
  7. data/README.md +152 -0
  8. data/Rakefile +2 -0
  9. data/bin/zapata +20 -0
  10. data/lib/zapata.rb +91 -0
  11. data/lib/zapata/analyst.rb +34 -0
  12. data/lib/zapata/core/collector.rb +9 -0
  13. data/lib/zapata/core/loader.rb +38 -0
  14. data/lib/zapata/core/reader.rb +10 -0
  15. data/lib/zapata/core/writer.rb +33 -0
  16. data/lib/zapata/db.rb +32 -0
  17. data/lib/zapata/diver.rb +81 -0
  18. data/lib/zapata/predictor/args.rb +94 -0
  19. data/lib/zapata/predictor/chooser.rb +27 -0
  20. data/lib/zapata/primitive/arg.rb +24 -0
  21. data/lib/zapata/primitive/array.rb +39 -0
  22. data/lib/zapata/primitive/base.rb +28 -0
  23. data/lib/zapata/primitive/basic.rb +22 -0
  24. data/lib/zapata/primitive/casgn.rb +15 -0
  25. data/lib/zapata/primitive/const.rb +15 -0
  26. data/lib/zapata/primitive/def.rb +33 -0
  27. data/lib/zapata/primitive/defs.rb +32 -0
  28. data/lib/zapata/primitive/hash.rb +31 -0
  29. data/lib/zapata/primitive/ivar.rb +6 -0
  30. data/lib/zapata/primitive/klass.rb +34 -0
  31. data/lib/zapata/primitive/lvar.rb +24 -0
  32. data/lib/zapata/primitive/missing.rb +17 -0
  33. data/lib/zapata/primitive/modul.rb +20 -0
  34. data/lib/zapata/primitive/nil.rb +16 -0
  35. data/lib/zapata/primitive/optarg.rb +18 -0
  36. data/lib/zapata/primitive/raw.rb +16 -0
  37. data/lib/zapata/primitive/send.rb +48 -0
  38. data/lib/zapata/primitive/sklass.rb +20 -0
  39. data/lib/zapata/primitive/var.rb +25 -0
  40. data/lib/zapata/printer.rb +93 -0
  41. data/lib/zapata/rzpec/runner.rb +67 -0
  42. data/lib/zapata/rzpec/writer.rb +115 -0
  43. data/lib/zapata/version.rb +3 -0
  44. data/spec/array_spec.rb +37 -0
  45. data/spec/definition_spec.rb +43 -0
  46. data/spec/hash_spec.rb +43 -0
  47. data/spec/klass_types_spec.rb +55 -0
  48. data/spec/send_spec.rb +31 -0
  49. data/spec/simple_types_spec.rb +90 -0
  50. data/spec/spec_helper.rb +124 -0
  51. data/spec/support/rails_test_app/.gitignore +16 -0
  52. data/spec/support/rails_test_app/.rspec +3 -0
  53. data/spec/support/rails_test_app/Gemfile +45 -0
  54. data/spec/support/rails_test_app/Gemfile.lock +200 -0
  55. data/spec/support/rails_test_app/README.md +3 -0
  56. data/spec/support/rails_test_app/Rakefile +6 -0
  57. data/spec/support/rails_test_app/app/assets/images/.keep +0 -0
  58. data/spec/support/rails_test_app/app/assets/javascripts/application.js +16 -0
  59. data/spec/support/rails_test_app/app/assets/stylesheets/application.css +15 -0
  60. data/spec/support/rails_test_app/app/controllers/application_controller.rb +5 -0
  61. data/spec/support/rails_test_app/app/controllers/concerns/.keep +0 -0
  62. data/spec/support/rails_test_app/app/helpers/application_helper.rb +2 -0
  63. data/spec/support/rails_test_app/app/mailers/.keep +0 -0
  64. data/spec/support/rails_test_app/app/models/.keep +0 -0
  65. data/spec/support/rails_test_app/app/models/concerns/.keep +0 -0
  66. data/spec/support/rails_test_app/app/models/robot_to_test.rb +49 -0
  67. data/spec/support/rails_test_app/app/models/test_array.rb +34 -0
  68. data/spec/support/rails_test_app/app/models/test_const.rb +14 -0
  69. data/spec/support/rails_test_app/app/models/test_definition.rb +38 -0
  70. data/spec/support/rails_test_app/app/models/test_float.rb +14 -0
  71. data/spec/support/rails_test_app/app/models/test_hash.rb +39 -0
  72. data/spec/support/rails_test_app/app/models/test_int.rb +14 -0
  73. data/spec/support/rails_test_app/app/models/test_send.rb +75 -0
  74. data/spec/support/rails_test_app/app/models/test_str.rb +14 -0
  75. data/spec/support/rails_test_app/app/models/test_sym.rb +14 -0
  76. data/spec/support/rails_test_app/app/models/testing_module/bare.rb +6 -0
  77. data/spec/support/rails_test_app/app/models/testing_module/klass_methods.rb +47 -0
  78. data/spec/support/rails_test_app/app/models/testing_module/nested/inside.rb +8 -0
  79. data/spec/support/rails_test_app/app/views/layouts/application.html.erb +14 -0
  80. data/spec/support/rails_test_app/config.ru +4 -0
  81. data/spec/support/rails_test_app/config/application.rb +23 -0
  82. data/spec/support/rails_test_app/config/boot.rb +4 -0
  83. data/spec/support/rails_test_app/config/database.yml +25 -0
  84. data/spec/support/rails_test_app/config/environment.rb +5 -0
  85. data/spec/support/rails_test_app/config/environments/development.rb +37 -0
  86. data/spec/support/rails_test_app/config/environments/production.rb +83 -0
  87. data/spec/support/rails_test_app/config/environments/test.rb +39 -0
  88. data/spec/support/rails_test_app/config/initializers/backtrace_silencers.rb +7 -0
  89. data/spec/support/rails_test_app/config/initializers/cookies_serializer.rb +3 -0
  90. data/spec/support/rails_test_app/config/initializers/filter_parameter_logging.rb +4 -0
  91. data/spec/support/rails_test_app/config/initializers/inflections.rb +16 -0
  92. data/spec/support/rails_test_app/config/initializers/mime_types.rb +4 -0
  93. data/spec/support/rails_test_app/config/initializers/session_store.rb +3 -0
  94. data/spec/support/rails_test_app/config/initializers/wrap_parameters.rb +14 -0
  95. data/spec/support/rails_test_app/config/locales/en.yml +23 -0
  96. data/spec/support/rails_test_app/config/routes.rb +56 -0
  97. data/spec/support/rails_test_app/config/secrets.yml +22 -0
  98. data/spec/support/rails_test_app/db/seeds.rb +7 -0
  99. data/spec/support/rails_test_app/lib/assets/.keep +0 -0
  100. data/spec/support/rails_test_app/lib/tasks/.keep +0 -0
  101. data/spec/support/rails_test_app/log/.keep +0 -0
  102. data/spec/support/rails_test_app/public/404.html +67 -0
  103. data/spec/support/rails_test_app/public/422.html +67 -0
  104. data/spec/support/rails_test_app/public/500.html +66 -0
  105. data/spec/support/rails_test_app/public/favicon.ico +0 -0
  106. data/spec/support/rails_test_app/public/robots.txt +5 -0
  107. data/spec/support/rails_test_app/spec/models/robot_to_test_spec.rb +33 -0
  108. data/spec/support/rails_test_app/spec/models/test_array_spec.rb +27 -0
  109. data/spec/support/rails_test_app/spec/models/test_const_spec.rb +11 -0
  110. data/spec/support/rails_test_app/spec/models/test_definition_spec.rb +31 -0
  111. data/spec/support/rails_test_app/spec/models/test_float_spec.rb +11 -0
  112. data/spec/support/rails_test_app/spec/models/test_hash_spec.rb +31 -0
  113. data/spec/support/rails_test_app/spec/models/test_int_spec.rb +11 -0
  114. data/spec/support/rails_test_app/spec/models/test_send_spec.rb +53 -0
  115. data/spec/support/rails_test_app/spec/models/test_str_spec.rb +11 -0
  116. data/spec/support/rails_test_app/spec/models/test_sym_spec.rb +11 -0
  117. data/spec/support/rails_test_app/spec/models/testing_module/bare_spec.rb +7 -0
  118. data/spec/support/rails_test_app/spec/models/testing_module/klass_methods_spec.rb +19 -0
  119. data/spec/support/rails_test_app/spec/models/testing_module/nested/inside_spec.rb +7 -0
  120. data/spec/support/rails_test_app/spec/rails_helper.rb +43 -0
  121. data/spec/support/rails_test_app/spec/spec_helper.rb +78 -0
  122. data/spec/support/rails_test_app/test/controllers/.keep +0 -0
  123. data/spec/support/rails_test_app/test/fixtures/.keep +0 -0
  124. data/spec/support/rails_test_app/test/helpers/.keep +0 -0
  125. data/spec/support/rails_test_app/test/integration/.keep +0 -0
  126. data/spec/support/rails_test_app/test/mailers/.keep +0 -0
  127. data/spec/support/rails_test_app/test/models/.keep +0 -0
  128. data/spec/support/rails_test_app/test/test_helper.rb +13 -0
  129. data/spec/support/rails_test_app/vendor/assets/javascripts/.keep +0 -0
  130. data/spec/support/rails_test_app/vendor/assets/stylesheets/.keep +0 -0
  131. data/zapata.gemspec +34 -0
  132. metadata +446 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c4947c74075c16975810dfe03d6b0708dbae7214
4
+ data.tar.gz: fd9187d034ba8b411bd8d9d47bd676aa0d4d08ed
5
+ SHA512:
6
+ metadata.gz: 5ce92767f6e47248793cddd5a5cc21ec911c5f247c5a809a0747e65a94707e7521648af0bccac6774fc77a9c641368c1bea8d0221b66f8cbe09d494e538f8b56
7
+ data.tar.gz: c9840ed16514a3bd7eaf0aceaddea7fa5154c818a4e7099a57249674ba3d5dac5bd7a3543b21709038567a76298dd5087287863401c371462b34f20534cf050a
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,5 @@
1
+ 1. [Fork it](https://github.com/Nedomas/zapata/fork)
2
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
3
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
4
+ 4. Push to the branch (`git push origin my-new-feature`)
5
+ 5. Create a new Pull Request
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zapata.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Domas
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Zapata
2
+
3
+ Who has time to write tests? This is a revolutional tool to make them write
4
+ themselves.
5
+
6
+ ![Emiliano Zapata](https://cloud.githubusercontent.com/assets/1877286/3753719/af3bfec2-1814-11e4-8790-242c2b26a8e9.jpg)
7
+
8
+ # What is your problem?
9
+
10
+ There comes a day where you have this bullshit class ``RobotToTest``. We need
11
+ tests. :shipit:
12
+
13
+ ```ruby
14
+ class RobotToTest
15
+ def initialize(human_name, cv)
16
+ @name = robot_name(human_name)
17
+ end
18
+
19
+ def robot_name(human_name)
20
+ "#{self.class.prefix}_#{human_name}"
21
+ end
22
+
23
+ def cv
24
+ { planets: planets }
25
+ end
26
+
27
+ def nested_fun_objects(fun_objects)
28
+ 'It was fun'
29
+ end
30
+
31
+ def self.prefix
32
+ 'Robot'
33
+ end
34
+
35
+ private
36
+
37
+ def planets
38
+ ['Mars', Human.home]
39
+ end
40
+
41
+ def fun_objects
42
+ [%i(array in array), { hash: nested_hash }]
43
+ end
44
+
45
+ def nested_hash
46
+ { in_hash: { in: array } }
47
+ end
48
+
49
+ def array
50
+ %w(array)
51
+ end
52
+ end
53
+
54
+ # just another class to analyze
55
+ class Human
56
+ def initialize
57
+ human_name = 'Emiliano'
58
+ end
59
+
60
+ def self.home
61
+ 'Earth'
62
+ end
63
+ end
64
+ ```
65
+
66
+ ## Solving it
67
+
68
+ You run ``zapata generate app/models/robot_to_test.rb`` and pop the champagne.
69
+ Zapata generated ``spec/models/robot_to_test_spec.rb`` for you.
70
+
71
+ ```ruby
72
+ describe RobotToTest do
73
+ let(:robot_to_test) do
74
+ RobotToTest.new('Emiliano', { planets: ['Mars', Human.home] })
75
+ end
76
+
77
+ it '#robot_name' do
78
+ expect(robot_to_test.robot_name('Emiliano')).to eq('Robot_Emiliano')
79
+ end
80
+
81
+ it '#cv' do
82
+ expect(robot_to_test.cv).to eq({ planets: ['Mars', 'Earth'] })
83
+ end
84
+
85
+ it '#nested_fun_objects' do
86
+ expect(robot_to_test.nested_fun_objects([
87
+ [:array, :in, :array],
88
+ {
89
+ hash: {
90
+ in_hash: {
91
+ in: ['array']
92
+ }
93
+ }
94
+ }
95
+ ])).to eq('It was fun')
96
+ end
97
+
98
+ it '#prefix' do
99
+ expect(RobotToTest.prefix).to eq('Robot')
100
+ end
101
+ end
102
+ ```
103
+
104
+ ## What does it do?
105
+
106
+ It tries to write a passing RSpec spec off the bat. It does fancy analysis
107
+ to predict the values it could feed to the API of a class.
108
+
109
+ __To be more specific:__
110
+ - Analyzes all vars and methods definitions in ``app/models``
111
+ - Checks what arguments does a testable method in ``app/models/robot_to_test.rb`` need
112
+ - Searches for such variable or method name in methods in analyzed
113
+ - Selects the most probable value by how many times it was repeated in code
114
+ - Runs the RSpec and fills in the expected values of the test with those returned by RSpec
115
+
116
+ For more things it can currently do check
117
+ https://github.com/Nedomas/zapata/tree/master/spec
118
+
119
+ ## Installation
120
+
121
+ It should be as easy as
122
+ ```sh
123
+ gem install zapata
124
+ ```
125
+
126
+ or
127
+
128
+ ```ruby
129
+ gem 'zapata', groups: %w(development test)
130
+ ```
131
+
132
+ ## Collaboration :heart:
133
+
134
+ I know that code analyzing is a sexy sphere to work on for many developers.
135
+ So here it is - a sexy project where you can realize your wet dreams about magic
136
+ in Ruby.
137
+
138
+ To install, run:
139
+ ```sh
140
+ git clone https://github.com/Nedomas/zapata
141
+ cd zapata
142
+ bundle exec rake install
143
+ ```
144
+
145
+ For specs, run:
146
+ ```sh
147
+ bundle exec rspec --patern "spec/*_spec.rb"
148
+ ```
149
+
150
+ ## Copyright
151
+ Copyright (c) 2014 Domas.
152
+ See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/zapata ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require_relative '../lib/zapata'
6
+
7
+ Slop.parse do
8
+ banner 'Usage: zapata [options]'
9
+
10
+ on '--help', '-h' do
11
+ puts help
12
+ end
13
+
14
+ command 'generate' do
15
+ run do |opts, args|
16
+ spec_filename = Zapata::Revolutionist.generate(args.shift)
17
+ puts "Its done, comrades. File #{spec_filename} was generated."
18
+ end
19
+ end
20
+ end
data/lib/zapata.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'parser/current'
2
+ require 'unparser'
3
+ require 'pry'
4
+ require 'pry-stack_explorer'
5
+ require 'rails'
6
+ require 'require_all'
7
+ require 'file/temp'
8
+ require 'open3'
9
+
10
+ require_rel 'zapata/core'
11
+ require_rel 'zapata/predictor'
12
+ require_rel 'zapata/primitive'
13
+ require_rel 'zapata/rzpec'
14
+ require_relative 'zapata/analyst'
15
+ require_relative 'zapata/diver'
16
+ require_relative 'zapata/db'
17
+ require_relative 'zapata/printer'
18
+ require_relative 'zapata/version'
19
+
20
+ module Zapata
21
+ class Revolutionist
22
+ class << self
23
+ attr_accessor :analysis, :analysis_as_array
24
+
25
+ def generate(filename)
26
+ dirs = %w(app/models)
27
+ file_list = Core::Collector.expand_dirs_to_files(dirs)
28
+
29
+ # files = %w(app/models/actual_fragment.rb app/models/ical.rb app/models/calendar/balance_transfer.rb)
30
+
31
+ new(file_list).generate_rspec_for(filename, spec_filename(filename))
32
+ end
33
+
34
+ def init_analysis_as_array
35
+ @analysis_as_array = analysis.values.flatten
36
+ end
37
+
38
+ def spec_filename(filename)
39
+ filename.gsub('app/', 'spec/').gsub('.rb', '_spec.rb')
40
+ end
41
+ end
42
+
43
+ def initialize(file_list)
44
+ Core::Loader.load_spec_helper
45
+ self.class.analysis = analyze_multiple(file_list)
46
+ end
47
+
48
+ def analyze_multiple(files)
49
+ total = files.size.to_s
50
+
51
+ files.each_with_object({}).with_index do |(filename, obj), i|
52
+ puts "[#{adjusted_current(i, total)}/#{total}] Analyzing: #{filename}"
53
+ obj[filename] = Analyst.analyze(filename)
54
+ end
55
+ end
56
+
57
+ def adjusted_current(i, total)
58
+ "#{i}".rjust(total.size)
59
+ end
60
+
61
+ def generate_rspec_for(filename, spec_filename)
62
+ unless self.class.analysis[filename]
63
+ self.class.analysis[filename] = Analyst.analyze(filename)
64
+ end
65
+
66
+ self.class.init_analysis_as_array
67
+
68
+ code = Core::Reader.parse(filename)
69
+
70
+ global_analysis = Revolutionist.analysis_as_array
71
+ # first run
72
+ tmp_spec_filename = File::Temp.new(false).path
73
+ RZpec::Writer.new(tmp_spec_filename, code, self.class.analysis[filename], global_analysis)
74
+
75
+ save_spec_file(tmp_spec_filename, spec_filename)
76
+ spec_analysis = RZpec::Runner.new(spec_filename)
77
+
78
+ # second run with RSpec results
79
+ RZpec::Writer.new(tmp_spec_filename, code, self.class.analysis[filename], global_analysis, spec_analysis)
80
+ save_spec_file(tmp_spec_filename, spec_filename)
81
+ end
82
+
83
+ def save_spec_file(tmp_spec_filename, spec_filename)
84
+ spec_path = "#{Dir.pwd}/#{spec_filename}"
85
+ spec_dir = spec_path.split('/')[0...-1].join('/')
86
+ FileUtils.mkdir_p(spec_dir)
87
+ FileUtils.cp(tmp_spec_filename, spec_path)
88
+ spec_filename
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,34 @@
1
+ module Zapata
2
+ class Analyst
3
+ attr_reader :result
4
+
5
+ def self.analyze(filename)
6
+ code = Core::Reader.parse(filename)
7
+ analyst = Analyst.new(code)
8
+ result = analyst.result.dup
9
+ analyst.clean
10
+ result
11
+ end
12
+
13
+ def initialize(code)
14
+ # class dive
15
+ Diver.search_for(:klass)
16
+ Diver.dive(code)
17
+ # var dive
18
+ Diver.search_for(:var)
19
+ Diver.dive(code)
20
+ # def dive
21
+ Diver.search_for(:def)
22
+ Diver.dive(code)
23
+ # send dive
24
+ Diver.search_for(:send)
25
+ Diver.dive(code)
26
+
27
+ @result = DB.all
28
+ end
29
+
30
+ def clean
31
+ DB.destroy_all
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module Zapata
2
+ module Core
3
+ class Collector
4
+ def self.expand_dirs_to_files(dirs)
5
+ dirs.map { |dir| Dir["#{dir}/*.rb"] }.flatten
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ module Zapata
2
+ module Core
3
+ class Loader
4
+ class << self
5
+ def rails_helper_path
6
+ File.expand_path("#{Dir.pwd}/spec/rails_helper", __FILE__)
7
+ end
8
+
9
+ def spec_helper_path
10
+ File.expand_path("#{Dir.pwd}/spec/spec_helper", __FILE__)
11
+ end
12
+
13
+ def helper_name
14
+ if File.exist?("#{rails_helper_path}.rb")
15
+ 'rails_helper'
16
+ elsif File.exist?("#{spec_helper_path}.rb")
17
+ 'spec_helper'
18
+ else
19
+ raise 'Was not able to load nor rails_helper, nor spec_helper'
20
+ end
21
+ end
22
+
23
+ def full_helper_path
24
+ paths = {
25
+ rails_helper: rails_helper_path,
26
+ spec_helper: spec_helper_path,
27
+ }.freeze
28
+
29
+ paths[helper_name.to_sym]
30
+ end
31
+
32
+ def load_spec_helper
33
+ require "#{full_helper_path}.rb"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ module Zapata
2
+ module Core
3
+ class Reader
4
+ def self.parse(filename)
5
+ plain_text_code = File.open(filename).read
6
+ Parser::CurrentRuby.parse(plain_text_code)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ module Zapata
2
+ module Core
3
+ class Writer
4
+ def initialize(filename)
5
+ @filename = filename
6
+ @padding = 0
7
+ clean
8
+ end
9
+
10
+ def clean
11
+ file = File.open(@filename, 'w')
12
+ file.write('')
13
+ file.close
14
+ end
15
+
16
+ def append_line(line = '')
17
+ @padding -= 1 if word_exists?(line, 'end')
18
+
19
+ padding_to_use = @padding
20
+ padding_to_use = 0 if line.empty?
21
+ file = File.open(@filename, 'ab+')
22
+ file.puts("#{' ' * padding_to_use}#{line}")
23
+ file.close
24
+
25
+ @padding += 1 if word_exists?(line, 'do')
26
+ end
27
+
28
+ def word_exists?(string, word)
29
+ !!/\b(?:#{word})\b/.match(string)
30
+ end
31
+ end
32
+ end
33
+ end