erector_to_fortitude 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9cded875e3387ed11fd00281a2936de45d37374
4
+ data.tar.gz: 6f2487e34aed2cbbd99a7ac3b8f4ccbd5f6ca77b
5
+ SHA512:
6
+ metadata.gz: 6db22dda91469c94c42f5a784aaecfd67d378b413f9ca6b6cbf28e156362014032d5272544495e1f29d72d68d8fc4ebc3d163c94059d9597daa9d85c17834ea8
7
+ data.tar.gz: 00c9c44ffac2af7f6aab976df3622d48e959b59f782783402039f6270ba2bf5947457dca35c7af8e5d9aa5f17d794902a1d00c95eb2816ad4c18794f2eb6e65e
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,4 @@
1
+ guard :rspec, cmd: 'bundle exec rspec', failed_mode: :focus do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/erector_to_fortitude/converter_spec.rb" }
4
+ end
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ Erector to Fortitude
2
+ ----
3
+
4
+ Converts Erector views to Fortitude syntax. In practice, this means assigning IDs and classes in the options hash: https://github.com/ageweke/fortitude/blob/master/README-erector.md#what-doesnt-it-support
5
+
6
+ ## Usage
7
+
8
+ ```
9
+ bin/erector_to_fortitude path/to/views
10
+ ```
11
+
12
+ ## Known issues
13
+
14
+ - Can't transform the contents of a proc that's the value of a hash (!??)
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ here = File.expand_path(File.dirname(__FILE__))
4
+
5
+ if File.directory?("#{here}/../lib/erector_to_fortitude")
6
+ $:.unshift "#{here}/../lib"
7
+ end
8
+
9
+ require 'erector_to_fortitude'
10
+
11
+ filepaths = []
12
+
13
+ ARGV.each do |arg|
14
+ if File.directory?(arg)
15
+ arg = arg.gsub(/\/$/, '')
16
+ Dir["#{arg}/**/*.rb"].each do |file|
17
+ filepaths << file
18
+ end
19
+ elsif File.exist?(arg)
20
+ filepaths << arg
21
+ else
22
+ puts "Didn't know how to parse the argument \"#{arg}\""
23
+ end
24
+ end
25
+
26
+ puts "Converting #{filepaths.length} files"
27
+
28
+ filepaths.each do |fp|
29
+ puts "Converting #{fp}..."
30
+ new_code = ErectorToFortitude::Converter.convert(File.read(fp))
31
+ File.open(fp, 'w') { |f| f.write(new_code) }
32
+ end
33
+
34
+ puts 'Done!'
@@ -0,0 +1,25 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require 'erector_to_fortitude/version'
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = 'erector_to_fortitude'
9
+ s.version = ErectorToFortitude::VERSION
10
+ s.required_ruby_version = Gem::Requirement.new('>= 2.0.0')
11
+ s.authors = ['Adam Becker']
12
+ s.summary = 'Converts Erector views to Fortitude syntax.'
13
+ s.email = 'adam@dobt.co'
14
+ s.license = 'MIT'
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {features,spec}/*`.split("\n")
17
+ s.homepage = 'http://github.com/ajb/erector_to_fortitude'
18
+
19
+ s.add_dependency 'parser'
20
+
21
+ s.add_development_dependency 'pry'
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'guard'
24
+ s.add_development_dependency 'guard-rspec'
25
+ end
@@ -0,0 +1,13 @@
1
+ module ErectorToFortitude
2
+ class Converter
3
+ def self.convert(code)
4
+ buffer = Parser::Source::Buffer.new('(example)')
5
+ buffer.source = code
6
+ parser = Parser::CurrentRuby.new
7
+ ast = parser.parse(buffer)
8
+ rewriter = Rewriter.new
9
+
10
+ rewriter.rewrite(buffer, ast)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,115 @@
1
+ module ErectorToFortitude
2
+ # From https://github.com/erector/erector/blob/37d38613fd1f485988150383a29db6a72a642d42/lib/erector/html_widget.rb#L66
3
+ HTML_TAGS = %w(
4
+ area
5
+ base
6
+ br
7
+ col
8
+ embed
9
+ frame
10
+ hr
11
+ img
12
+ input
13
+ link
14
+ meta
15
+ param
16
+ a
17
+ abbr
18
+ acronym
19
+ address
20
+ article
21
+ aside
22
+ audio
23
+ b
24
+ bdo
25
+ big
26
+ blockquote
27
+ body
28
+ button
29
+ canvas
30
+ caption
31
+ center
32
+ cite
33
+ code
34
+ colgroup
35
+ command
36
+ datalist
37
+ dd
38
+ del
39
+ details
40
+ dfn
41
+ dialog
42
+ div
43
+ dl
44
+ dt
45
+ em
46
+ fieldset
47
+ figure
48
+ footer
49
+ form
50
+ frameset
51
+ h1
52
+ h2
53
+ h3
54
+ h4
55
+ h5
56
+ h6
57
+ head
58
+ header
59
+ hgroup
60
+ html
61
+ i
62
+ iframe
63
+ ins
64
+ keygen
65
+ kbd
66
+ label
67
+ legend
68
+ li
69
+ map
70
+ mark
71
+ meter
72
+ nav
73
+ noframes
74
+ noscript
75
+ object
76
+ ol
77
+ optgroup
78
+ option
79
+ p
80
+ pre
81
+ progress
82
+ q
83
+ ruby
84
+ rt
85
+ rp
86
+ s
87
+ samp
88
+ script
89
+ section
90
+ select
91
+ small
92
+ source
93
+ span
94
+ strike
95
+ strong
96
+ style
97
+ sub
98
+ sup
99
+ table
100
+ tbody
101
+ td
102
+ textarea
103
+ tfoot
104
+ th
105
+ thead
106
+ time
107
+ title
108
+ tr
109
+ tt
110
+ u
111
+ ul
112
+ var
113
+ video
114
+ )
115
+ end
@@ -0,0 +1,108 @@
1
+ require 'pry'
2
+
3
+ module ErectorToFortitude
4
+ class Rewriter < Parser::Rewriter
5
+ def on_send(node)
6
+ # Why is this necessary?
7
+ return unless node.children.length > 1
8
+
9
+ # How do I explain this? lol
10
+ return unless node.children[0]
11
+
12
+ tag_node = get_first_node(node.children[0])
13
+
14
+ # The tag method is an instance method
15
+ return unless tag_node.children[0] == nil
16
+
17
+ # Validate tag name
18
+ return unless ErectorToFortitude::HTML_TAGS.include?(tag_node.children[1].to_s)
19
+
20
+ ids = []
21
+ classes = []
22
+
23
+ get_classes_and_ids_sent(node).each do |class_or_id|
24
+ if class_or_id[-1] == '!'
25
+ ids << class_or_id[0..-2]
26
+ else
27
+ classes << class_or_id
28
+ end
29
+ end
30
+
31
+ new_opts = []
32
+
33
+ if classes.length > 0
34
+ new_opts << %{class: '#{classes.join(' ')}'}
35
+ end
36
+
37
+ if ids.length > 0
38
+ new_opts << %{id: '#{ids.join(' ')}'}
39
+ end
40
+
41
+ new_opt_str = new_opts.join(', ')
42
+
43
+ # Replace the existing dots
44
+ get_sends(node).each do |child|
45
+ replace child.loc.dot, ''
46
+ replace child.loc.selector, ''
47
+ end
48
+
49
+ if (text_node = get_node_after_classes_and_ids(node)) && text_node.is_a?(Parser::AST::Node) && text_node.type != :hash
50
+
51
+ insert_after text_node.loc.expression, ', ' + new_opt_str
52
+
53
+ # Add class to existing hash
54
+ elsif node.children[2] && node.children[2].type == :hash
55
+ insert_before node.children[2].children[0].loc.expression, new_opt_str + ', '
56
+
57
+ # Add a new options hash
58
+ else
59
+ # Remove the dot
60
+ insert_after node.loc.selector, "(#{new_opt_str})"
61
+ end
62
+ end
63
+
64
+ def get_first_node(node)
65
+ while node.children[0].is_a?(Parser::AST::Node) && node.children[0].type == :send
66
+ node = node.children[0]
67
+ end
68
+
69
+ node
70
+ end
71
+
72
+ def get_sends(node)
73
+ arr = []
74
+
75
+ while node.children[0] && node.children[0].type == :send
76
+ arr << node
77
+ node = node.children[0]
78
+ end
79
+
80
+ arr
81
+ end
82
+
83
+ def get_classes_and_ids_sent(node)
84
+ arr = []
85
+
86
+ while node.children[0] && node.children[0].type == :send
87
+ arr << node.children[1]
88
+ node = node.children[0]
89
+ end
90
+
91
+ arr.reverse
92
+ end
93
+
94
+ def get_node_after_classes_and_ids(node)
95
+ found_classes_and_ids = false
96
+
97
+ node.children.each do |child|
98
+ if child.is_a?(Symbol)
99
+ found_classes_and_ids = true
100
+ end
101
+
102
+ if found_classes_and_ids && !child.is_a?(Symbol)
103
+ return child
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ module ErectorToFortitude
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,8 @@
1
+ module ErectorToFortitude
2
+ end
3
+
4
+ require 'parser'
5
+ require 'parser/current'
6
+ require 'erector_to_fortitude/converter'
7
+ require 'erector_to_fortitude/rewriter'
8
+ require 'erector_to_fortitude/html_tags'
data/script/cibuild ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ bundle exec rspec
data/script/release ADDED
@@ -0,0 +1,38 @@
1
+ #!/bin/sh
2
+ # Tag and push a release.
3
+
4
+ set -e
5
+
6
+ # Make sure we're in the project root.
7
+
8
+ cd $(dirname "$0")/..
9
+
10
+ # Build a new gem archive.
11
+
12
+ rm -rf erector_to_fortitude-*.gem
13
+ gem build -q erector_to_fortitude.gemspec
14
+
15
+ # Make sure we're on the master branch.
16
+
17
+ (git branch | grep -q '* master') || {
18
+ echo "Only release from the master branch."
19
+ exit 1
20
+ }
21
+
22
+ # Figure out what version we're releasing.
23
+
24
+ tag=v`ls erector_to_fortitude-*.gem | sed 's/^erector_to_fortitude-\(.*\)\.gem$/\1/'`
25
+
26
+ # Make sure we haven't released this version before.
27
+
28
+ git fetch -t origin
29
+
30
+ (git tag -l | grep -q "$tag") && {
31
+ echo "Whoops, there's already a '${tag}' tag."
32
+ exit 1
33
+ }
34
+
35
+ # Tag it and bag it.
36
+
37
+ gem push erector_to_fortitude-*.gem && git tag "$tag" &&
38
+ git push origin master && git push origin "$tag"
@@ -0,0 +1,232 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ErectorToFortitude::Converter do
4
+ it 'converts a basic class send' do
5
+ input = <<END
6
+ div.foo {
7
+ text 'hi'
8
+ }
9
+ END
10
+
11
+ output = code = <<END
12
+ div(class: 'foo') {
13
+ text 'hi'
14
+ }
15
+ END
16
+
17
+ expect(described_class.convert(input)).to eq output
18
+ end
19
+
20
+ it 'converts multiple classes' do
21
+ input = <<END
22
+ div.foo.bar.baz {
23
+ text 'hi'
24
+ }
25
+ END
26
+
27
+ output = code = <<END
28
+ div(class: 'foo bar baz') {
29
+ text 'hi'
30
+ }
31
+ END
32
+
33
+ expect(described_class.convert(input)).to eq output
34
+ end
35
+
36
+ it 'converts on non-div tags' do
37
+ input = <<END
38
+ span.foo {
39
+ text 'hi'
40
+ }
41
+ END
42
+
43
+ output = code = <<END
44
+ span(class: 'foo') {
45
+ text 'hi'
46
+ }
47
+ END
48
+
49
+ expect(described_class.convert(input)).to eq output
50
+ end
51
+
52
+ it 'ignores non-erector stuffs' do
53
+ input = <<END
54
+ span {
55
+ foos = Foo.with_deleted.all
56
+ text foos.count
57
+ bar.baz!
58
+ }
59
+ END
60
+
61
+ output = code = <<END
62
+ span {
63
+ foos = Foo.with_deleted.all
64
+ text foos.count
65
+ bar.baz!
66
+ }
67
+ END
68
+
69
+ expect(described_class.convert(input)).to eq output
70
+ end
71
+
72
+ it 'converts a basic id send' do
73
+ input = <<END
74
+ div.foo! {
75
+ text 'hi'
76
+ }
77
+ END
78
+
79
+ output = code = <<END
80
+ div(id: 'foo') {
81
+ text 'hi'
82
+ }
83
+ END
84
+
85
+ expect(described_class.convert(input)).to eq output
86
+ end
87
+
88
+ it 'handles existing hash options' do
89
+ input = <<END
90
+ div.foo('data-bar' => 'baz') {
91
+ text 'hi'
92
+ }
93
+ END
94
+
95
+ output = code = <<END
96
+ div(class: 'foo', 'data-bar' => 'baz') {
97
+ text 'hi'
98
+ }
99
+ END
100
+
101
+ expect(described_class.convert(input)).to eq output
102
+ end
103
+
104
+ it 'handles complex existing hash options' do
105
+ input = <<END
106
+ div.foo.bar.baz.booz!('data-bar' => 'baz') {
107
+ text 'hi'
108
+ }
109
+ END
110
+
111
+ output = code = <<END
112
+ div(class: 'foo bar baz', id: 'booz', 'data-bar' => 'baz') {
113
+ text 'hi'
114
+ }
115
+ END
116
+
117
+ expect(described_class.convert(input)).to eq output
118
+ end
119
+
120
+ it 'handles a text argument' do
121
+ input = <<END
122
+ span.foo 'Bar'
123
+ END
124
+
125
+ output = code = <<END
126
+ span 'Bar', class: 'foo'
127
+ END
128
+
129
+ expect(described_class.convert(input)).to eq output
130
+ end
131
+
132
+ it 'handles a text argument with existing hash' do
133
+ input = <<END
134
+ span.foo 'bar', 'data-baz' => 'booz'
135
+ END
136
+
137
+ output = code = <<END
138
+ span 'bar', class: 'foo', 'data-baz' => 'booz'
139
+ END
140
+
141
+ expect(described_class.convert(input)).to eq output
142
+ end
143
+
144
+ it 'handles a dynamic text argument' do
145
+ input = <<END
146
+ span.foo x, 'data-baz' => 'booz'
147
+ END
148
+
149
+ output = code = <<END
150
+ span x, class: 'foo', 'data-baz' => 'booz'
151
+ END
152
+
153
+ expect(described_class.convert(input)).to eq output
154
+ end
155
+
156
+ it 'handles a complex dynamic text argument' do
157
+ input = <<END
158
+ span.foo x.z.y(yeah: 'man'), 'data-baz' => 'booz'
159
+ END
160
+
161
+ output = code = <<END
162
+ span x.z.y(yeah: 'man'), class: 'foo', 'data-baz' => 'booz'
163
+ END
164
+
165
+ expect(described_class.convert(input)).to eq output
166
+ end
167
+
168
+ it 'handles a text argument inside another node' do
169
+ input = <<END
170
+ div.bar {
171
+ span.foo x
172
+ }
173
+ END
174
+
175
+ output = code = <<END
176
+ div(class: 'bar') {
177
+ span x, class: 'foo'
178
+ }
179
+ END
180
+
181
+ expect(described_class.convert(input)).to eq output
182
+ end
183
+
184
+ it 'handles empty tags' do
185
+ input = <<END
186
+ div.bar
187
+ END
188
+
189
+ output = code = <<END
190
+ div(class: 'bar')
191
+ END
192
+
193
+ expect(described_class.convert(input)).to eq output
194
+ end
195
+
196
+ it 'handles code within an inline widget' do
197
+ input = <<END
198
+ Erector.inline {
199
+ div.foo 'bar'
200
+ }
201
+ END
202
+
203
+ output = code = <<END
204
+ Erector.inline {
205
+ div 'bar', class: 'foo'
206
+ }
207
+ END
208
+
209
+ expect(described_class.convert(input)).to eq output
210
+ end
211
+
212
+ # known issue
213
+ xit 'handles code inside proc values' do
214
+ input = <<END
215
+ bar({
216
+ proc: -> {
217
+ a.button.primary 'hi'
218
+ }
219
+ })
220
+ END
221
+
222
+ output = code = <<END
223
+ bar({
224
+ proc: -> {
225
+ a 'hi', class: 'button primary'
226
+ }
227
+ })
228
+ END
229
+
230
+ expect(described_class.convert(input)).to eq output
231
+ end
232
+ end
@@ -0,0 +1 @@
1
+ require 'erector_to_fortitude'
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: erector_to_fortitude
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Becker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parser
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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email: adam@dobt.co
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - ".gitignore"
90
+ - Gemfile
91
+ - Guardfile
92
+ - README.md
93
+ - bin/erector_to_fortitude
94
+ - erector_to_fortitude.gemspec
95
+ - lib/erector_to_fortitude.rb
96
+ - lib/erector_to_fortitude/converter.rb
97
+ - lib/erector_to_fortitude/html_tags.rb
98
+ - lib/erector_to_fortitude/rewriter.rb
99
+ - lib/erector_to_fortitude/version.rb
100
+ - script/cibuild
101
+ - script/release
102
+ - spec/lib/erector_to_fortitude/converter_spec.rb
103
+ - spec/spec_helper.rb
104
+ homepage: http://github.com/ajb/erector_to_fortitude
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.0.0
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.2.2
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Converts Erector views to Fortitude syntax.
128
+ test_files:
129
+ - spec/lib/erector_to_fortitude/converter_spec.rb
130
+ - spec/spec_helper.rb
131
+ has_rdoc: