eex2slime 0.3.0 → 1.0.0
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 +4 -4
- data/README.md +58 -8
- data/lib/eex2slime/command.rb +7 -5
- data/lib/eex2slime/converter.rb +33 -37
- data/lib/eex2slime/hpricot_monkeypatches.rb +34 -11
- data/lib/eex2slime/version.rb +1 -1
- data/lib/eex2slime.rb +9 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36918c220cf3167b9e2ee99ed463046f11c210bd
|
4
|
+
data.tar.gz: 34b61cc5e0e804843b428b1162f5bb579e0b4f85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd509471dbf78b58e891dae7b604761931e7c30ad60cbff8ea24812ebf228174bc6970888345ef02a621ea0db90f23350dd05e0fc9e9001342c2522da313ba91
|
7
|
+
data.tar.gz: c606b14331370634cd4e32590a16fbc9a86f1685356f06b08914ec73401e0002063d3fd205e74af37537eb9943e6d7e49d217ce139a7e1ac28b11b8922ae22ba
|
data/README.md
CHANGED
@@ -1,20 +1,32 @@
|
|
1
1
|
## EEx2Slime
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/eex2slime)
|
4
|
+
[](https://travis-ci.org/hedgesky/eex2slime)
|
5
|
+
|
3
6
|
Script for converting EEx templates to [Slime](http://slime-lang.com). Slime is a lightweight template language.
|
4
7
|
|
5
8
|
## Usage
|
6
9
|
|
7
|
-
You may convert files using the included executable `eex2slime
|
10
|
+
You may convert files using the included executable `eex2slime`:
|
11
|
+
|
12
|
+
```bash
|
13
|
+
$ gem install eex2slime
|
8
14
|
|
9
|
-
|
15
|
+
$ eex2slime foo.html.eex # outputs to foo.html.slime by default
|
16
|
+
$ eex2slime foo.html.eex bar.html.slime # outputs to bar.html.slime
|
17
|
+
$ eex2slime foo.html.eex - # outputs to stdout
|
18
|
+
$ cat foo.eex | eex2slime # input from stdin, outputs to stdout
|
19
|
+
$ eex2slime dir/ # convert all .eex files recursively
|
20
|
+
$ eex2slime --delete dir/ # delete .eex files after convertion. Be sure you have a backup!
|
21
|
+
```
|
10
22
|
|
11
|
-
|
12
|
-
--trace Show a full traceback on error
|
13
|
-
-d, --delete Delete EEx files
|
14
|
-
-h, --help Show this message
|
15
|
-
-v, --version Print version
|
23
|
+
Alternatively you could use the following API:
|
16
24
|
|
17
|
-
|
25
|
+
```ruby
|
26
|
+
require 'eex2slime'
|
27
|
+
EEx2Slime.convert('path/to/file')
|
28
|
+
EEx2Slime.convert_string('<nav class="navbar"></nav>')
|
29
|
+
```
|
18
30
|
|
19
31
|
## Installation
|
20
32
|
|
@@ -23,3 +35,41 @@ Alternatively, to convert files or strings on the fly in your application, you m
|
|
23
35
|
## Regards
|
24
36
|
|
25
37
|
Huge thanks to [Maiz Lulkin](https://github.com/joaomilho) and his original [html2slim repo](https://github.com/slim-template/html2slim).
|
38
|
+
|
39
|
+
## Does it really work?
|
40
|
+
|
41
|
+
It might fail in some cases, but in general yes, it does! I've checked it on the opersourced [changelog.com app](https://github.com/thechangelog/changelog.com). After a bit of preparing this tool finely converted all EEx templates.
|
42
|
+
|
43
|
+
CI runs tests on Rubies 2.2, 1.9.3. Ruby 1.8.7 isn't supported.
|
44
|
+
|
45
|
+
## Known issues
|
46
|
+
|
47
|
+
- Incorrect HTML will break inner HTML parser. Example (notice misplaced slash):
|
48
|
+
|
49
|
+
```html
|
50
|
+
<img width="75" / height="75">
|
51
|
+
```
|
52
|
+
|
53
|
+
- Nested interpolation won't play well with Slime. This:
|
54
|
+
|
55
|
+
```erb
|
56
|
+
<img src="<%= static_url(@conn, "/images/podcasts/#{@podcast.slug}.svg") %>">
|
57
|
+
```
|
58
|
+
|
59
|
+
should be rewritten to:
|
60
|
+
|
61
|
+
```erb
|
62
|
+
<% image_url = static_url(@conn, "/images/podcasts/#{@podcast.slug}.svg") %>
|
63
|
+
<img src="<%= image_url %>">
|
64
|
+
```
|
65
|
+
|
66
|
+
- This library doesn't support inline `if`'s interpolation:
|
67
|
+
|
68
|
+
```erb
|
69
|
+
<!-- such constructions aren't supported -->
|
70
|
+
<article class="<%= if index == 0 do %>is-active<% end %>"></article>
|
71
|
+
```
|
72
|
+
|
73
|
+
## License
|
74
|
+
|
75
|
+
This project uses MIT license.
|
data/lib/eex2slime/command.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# This class parses CLI arguments and runs converter.
|
2
|
+
|
1
3
|
require 'optparse'
|
2
4
|
require 'eex2slime'
|
3
5
|
|
@@ -14,10 +16,10 @@ module EEx2Slime
|
|
14
16
|
@opts.parse!(@args)
|
15
17
|
process!
|
16
18
|
exit 0
|
17
|
-
rescue
|
18
|
-
raise
|
19
|
-
$stderr.print "#{
|
20
|
-
$stderr.puts
|
19
|
+
rescue => error
|
20
|
+
raise error if @options[:trace] || SystemExit === error
|
21
|
+
$stderr.print "#{error.class}: " if error.class != RuntimeError
|
22
|
+
$stderr.puts error.message
|
21
23
|
$stderr.puts ' Use --trace for backtrace.'
|
22
24
|
exit 1
|
23
25
|
end
|
@@ -102,7 +104,7 @@ module EEx2Slime
|
|
102
104
|
else
|
103
105
|
$stdout
|
104
106
|
end
|
105
|
-
@options[:output].puts EEx2Slime.convert
|
107
|
+
@options[:output].puts EEx2Slime.convert(in_file)
|
106
108
|
@options[:output].close
|
107
109
|
|
108
110
|
File.delete(file) if @options[:delete]
|
data/lib/eex2slime/converter.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
1
|
+
# This class takes EEx string and replaces all embedded elixir with
|
2
|
+
# <elixir code="...">...</elixir> tags, which are parsed with Hpricot.
|
3
|
+
require_relative "hpricot_monkeypatches"
|
2
4
|
|
3
5
|
module EEx2Slime
|
4
|
-
class
|
6
|
+
class Converter
|
5
7
|
def self.from_stream(stream)
|
6
8
|
input =
|
7
9
|
if stream.is_a?(IO)
|
@@ -19,8 +21,8 @@ module EEx2Slime
|
|
19
21
|
prepare_else_statements!
|
20
22
|
prepare_elixir_condition_expressions!
|
21
23
|
prepare_end_statements!
|
22
|
-
prepare_regular_elixir_code!
|
23
24
|
prepare_elixir_inside_attributes!
|
25
|
+
prepare_regular_elixir_code!
|
24
26
|
@slime = Hpricot(@eex).to_slime
|
25
27
|
end
|
26
28
|
|
@@ -30,16 +32,11 @@ module EEx2Slime
|
|
30
32
|
|
31
33
|
private
|
32
34
|
|
33
|
-
def prepare_curly_blocks!
|
34
|
-
@eex.gsub!(/<%(.+?)\s*\{\s*(\|.+?\|)?\s*%>/) {
|
35
|
-
%(<%#{$1} do #{$2}%>)
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
35
|
def prepare_control_flow_statements!
|
40
|
-
|
41
|
-
|
42
|
-
}
|
36
|
+
regex1 = /<%(?:-\s+)?((\s*(case|if|for|unless) ((?:(?!%>).)+)?))-?%>/
|
37
|
+
regex2 = /<%(?:-\s+)?(((?:(?!%>).)+)?do\s*(\|.+?\|)?\s*)-?%>/
|
38
|
+
@eex.gsub!(regex1) { %(<elixir code="#{$1.gsub(/"/, '"')}">) }
|
39
|
+
@eex.gsub!(regex2) { %(<elixir code="#{$1.gsub(/"/, '"')}">) }
|
43
40
|
end
|
44
41
|
|
45
42
|
def prepare_elixir_anonymous_functions!
|
@@ -62,38 +59,37 @@ module EEx2Slime
|
|
62
59
|
@eex.gsub!(/<%=?\s*(end|}|end\s+-)\s*%>/, %(</elixir>))
|
63
60
|
end
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
# test string
|
72
|
-
# <div class="form <%= a() %>" data="<%= b() %>"></div>
|
62
|
+
# test string:
|
63
|
+
# <div class="form <%= a() %> " data="<%= b() %> another"></div>
|
64
|
+
# <%= another() %>
|
73
65
|
def prepare_elixir_inside_attributes!
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# (?:.(?!elixir))+ # but forbid spanning over other attributes
|
81
|
-
# )
|
82
|
-
# "><\/elixir>
|
83
|
-
# )
|
84
|
-
# /x
|
66
|
+
# =" ensure we are inside attributes
|
67
|
+
# ([^"]*) capture other attributes
|
68
|
+
# <%= ensure we are inside outputting elixir tag
|
69
|
+
# ((?:(?!%>).)+) capture code, don't span across multiple elixir tags
|
70
|
+
# \s* swallow spaces
|
71
|
+
# -?%> end of elixir tag
|
85
72
|
#
|
86
73
|
# Example match data:
|
87
74
|
# Match 1
|
88
75
|
# 1. form
|
89
|
-
# 2.
|
90
|
-
# 3. a()
|
76
|
+
# 2. a()
|
91
77
|
# Match 2
|
92
78
|
# 1.
|
93
|
-
# 2.
|
94
|
-
|
95
|
-
regex
|
96
|
-
|
79
|
+
# 2. b()
|
80
|
+
regex = /="([^"]*)<%=((?:(?!%>).)+)\s*-?%>/
|
81
|
+
@eex.gsub!(regex) {
|
82
|
+
# use variables, because gsub changes $1 and $2 values
|
83
|
+
attrs = $1
|
84
|
+
elixir = $2.gsub('"', """).strip
|
85
|
+
%Q(="#{attrs}\#{#{elixir}})
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def prepare_regular_elixir_code!
|
90
|
+
@eex.gsub!(/<%-?(.+?)\s*-?%>/m) {
|
91
|
+
%(<elixir code="#{$1.gsub(/"/, '"')}"></elixir>)
|
92
|
+
}
|
97
93
|
end
|
98
94
|
end
|
99
95
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# Patch Hpricot to support our custom <elixir> tags.
|
1
2
|
require 'hpricot'
|
2
3
|
|
3
4
|
Hpricot::XHTMLTransitional.tagset[:elixir] = [:code]
|
@@ -83,12 +84,12 @@ class Hpricot::Elem
|
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
87
|
+
private
|
88
|
+
|
86
89
|
def elixir?
|
87
90
|
name == "elixir"
|
88
91
|
end
|
89
92
|
|
90
|
-
private
|
91
|
-
|
92
93
|
def children_slime(lvl)
|
93
94
|
children
|
94
95
|
.map { |c| c.to_slime(lvl+1) }
|
@@ -130,7 +131,8 @@ class Hpricot::Elem
|
|
130
131
|
def slime_attributes
|
131
132
|
remove_css_class
|
132
133
|
remove_attribute('id')
|
133
|
-
|
134
|
+
return "" unless has_attributes?
|
135
|
+
"[#{attrs_with_restored_interpolation}]"
|
134
136
|
end
|
135
137
|
|
136
138
|
def has_attributes?
|
@@ -149,26 +151,47 @@ class Hpricot::Elem
|
|
149
151
|
name == "div"
|
150
152
|
end
|
151
153
|
|
154
|
+
def attrs_with_restored_interpolation
|
155
|
+
regex = /\#{([^{}]+)}/
|
156
|
+
attributes_as_html.to_s.strip.gsub(regex) do
|
157
|
+
code = $1.gsub(""", '"')
|
158
|
+
"\#{ #{code} }"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
152
162
|
def remove_css_class
|
153
163
|
if has_class? && cryptic_classes.any?
|
154
164
|
self["class"] = cryptic_classes.join(" ")
|
155
165
|
else
|
156
|
-
remove_attribute(
|
166
|
+
remove_attribute("class")
|
157
167
|
end
|
158
168
|
end
|
159
169
|
|
160
170
|
def non_cryptic_classes
|
161
|
-
|
162
|
-
|
163
|
-
|
171
|
+
crypto_analyzer.last
|
172
|
+
end
|
173
|
+
|
174
|
+
def cryptic_classes
|
175
|
+
crypto_analyzer.first
|
164
176
|
end
|
165
177
|
|
166
178
|
# We can have interpolation inside attributes.
|
167
179
|
# Such classes should always be in attributes section (not shortened)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
180
|
+
# This handles cituations like this:
|
181
|
+
# <div class="form foo-<%= error_class f, :slug %>-bar"></div>
|
182
|
+
def crypto_analyzer
|
183
|
+
return [[], []] unless has_attribute?("class")
|
184
|
+
@crypto_analyzer ||= begin
|
185
|
+
class_value = self["class"].strip
|
186
|
+
interpolation_regex = /[-\w]*\#{(?:[^{}]+)}[-\w]*/
|
187
|
+
interpolated_classes = class_value.scan(interpolation_regex)
|
188
|
+
class_value.gsub!(interpolation_regex, "")
|
189
|
+
|
190
|
+
crypt, non_crypt = class_value.split(/\s+/).partition do |klass|
|
191
|
+
klass.match(/[=#"&()]/)
|
192
|
+
end
|
193
|
+
[crypt + interpolated_classes, non_crypt]
|
194
|
+
end
|
172
195
|
end
|
173
196
|
end
|
174
197
|
|
data/lib/eex2slime/version.rb
CHANGED
data/lib/eex2slime.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
+
# This library converts EEx templates to Slime. It's based on html2slim
|
2
|
+
# library by @joaomilho. Usage examples are in README.
|
3
|
+
|
1
4
|
require_relative 'eex2slime/version'
|
2
5
|
require_relative 'eex2slime/converter'
|
3
6
|
|
4
7
|
module EEx2Slime
|
5
|
-
def self.convert
|
6
|
-
|
8
|
+
def self.convert(input)
|
9
|
+
Converter.from_stream(input).to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.convert_string(eex)
|
13
|
+
Converter.new(eex).to_s
|
7
14
|
end
|
8
15
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eex2slime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Chuchkalov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hpricot
|
@@ -81,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version:
|
84
|
+
version: 1.9.3
|
85
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|