erector_to_fortitude 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: