render_me_pretty 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0ca366dbc0b626c3bd1fa15b7d83f8d29ab4b22a0eabd35dc6d1c68604b0925
4
- data.tar.gz: 18a6fbec659aa7d6fde4053277aa10d5836d7703d38e2b9b29e78399a921b264
3
+ metadata.gz: 5fca5bd4ed5c7502ec8b72669e5fced039e90b8e4f1cdb6f47fdaab6f289e247
4
+ data.tar.gz: 26ecbd9090b108e5baf921cec068a06a2ac4057232d984792304e49d0d038304
5
5
  SHA512:
6
- metadata.gz: 71a16eef148da71913f34478c8981915f8844e4586344771fd490d21f61c7f5cbd3a22d83f5b61deedad188f04b696372cca8b8185687ab9e44e058751554a36
7
- data.tar.gz: 6e68c1e4fa8c5d1fd0e133b1e4d0ec44d708deaccd888b5ba23fadd49cec30d74b1918b6d48de921be49face3ed28013309d0bfac6695515f10dcb40904743a6
6
+ metadata.gz: bb38911b2da29bc35e67d648d7de31b17b74cdfd0b7a3b97bfbb6419a641d884c77d063d84ba9f4abd195f2fc6ebf7915e598b3b9b2b6ff18297e2cd6a6f601b
7
+ data.tar.gz: 74a63b170fcab819827e3f808f0b14c25925b162c123b9b7f519c39b2b77e07a858fe38c351fa3e08cfbc4ce6a52c5c70dc3a687f069993bc6348e8179ca253c
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [0.4.0]
7
+ - fix erb and context definitions, fix bug with empty variables={}
8
+ - improve original backtrace info, colorize exact line
9
+
10
+ ## [0.3.0]
11
+ - fix bug with empty variables={}
12
+ - fix erb and context definitions
13
+
6
14
  ## [0.2.0]
7
15
  - add RenderMePretty.result convenience class method
8
16
 
@@ -1,14 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- render_me_pretty (0.1.0)
4
+ render_me_pretty (0.3.0)
5
5
  activesupport
6
6
  colorize
7
+ tilt
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (5.1.4)
12
+ activesupport (5.1.5)
12
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
14
  i18n (~> 0.7)
14
15
  minitest (~> 5.1)
@@ -16,7 +17,7 @@ GEM
16
17
  colorize (0.8.1)
17
18
  concurrent-ruby (1.0.5)
18
19
  diff-lcs (1.3)
19
- i18n (0.9.4)
20
+ i18n (0.9.5)
20
21
  concurrent-ruby (~> 1.0)
21
22
  minitest (5.11.3)
22
23
  rake (12.3.0)
@@ -34,6 +35,7 @@ GEM
34
35
  rspec-support (~> 3.7.0)
35
36
  rspec-support (3.7.1)
36
37
  thread_safe (0.3.6)
38
+ tilt (2.0.8)
37
39
  tzinfo (1.2.5)
38
40
  thread_safe (~> 0.1)
39
41
 
data/README.md CHANGED
@@ -45,6 +45,26 @@ There's also a convenience class method:
45
45
  RenderMePretty.result("/path/to/tempate.erb", a: 5)
46
46
  ```
47
47
 
48
+ ### Custom Context
49
+
50
+ ```ruby
51
+ person = Person.new("tung")
52
+ erb = RenderMePretty::Erb.new("/path/to/tempate.erb", a: 3, context: person) } # passing context here
53
+ erb.render(a: 4)
54
+
55
+ person = Person.new("tung")
56
+ erb = RenderMePretty::Erb.new("/path/to/tempate.erb", a: 3) }
57
+ erb.render(person, a: 4) # passing context here
58
+ ```
59
+
60
+ The context's methods and instance variables are available in the ERB template. Variables passed at initialization time to `RenderMePretty::Erb.new` or at call time for `render` be set as instance variables to a clone of the original context object.
61
+
62
+ So in the case above, if there was an `@a` instance variable in the Person object, it will not get respected. Instead the value would be `@a = 4`.
63
+
64
+ ### Context
65
+
66
+ You can pass in a context object also. Examples:
67
+
48
68
  A few more examples are in the [erb_spec.rb](spec/lib/render_me_pretty/erb_spec.rb)
49
69
 
50
70
  ## Installation
@@ -1,11 +1,12 @@
1
1
  require "render_me_pretty/version"
2
+ require "active_support/core_ext/string"
3
+ require "colorize"
2
4
 
3
5
  module RenderMePretty
4
6
  autoload :Erb, 'render_me_pretty/erb'
5
- autoload :Context, 'render_me_pretty/context'
6
7
 
7
- def self.result(path, variables={})
8
- erb = Erb.new(path, variables={})
8
+ def result(path, variables={})
9
+ erb = Erb.new(path, variables)
9
10
  erb.render
10
11
  end
11
12
 
@@ -1,30 +1,154 @@
1
+ =begin
2
+ ## Usage examples:
3
+
4
+ Given an example template /path/to/template.erb that contains:
5
+
6
+ a: <%= @a %>
7
+
8
+ ### Variables at initialization
9
+
10
+ erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 1)
11
+ erb.render
12
+
13
+ Result: a: 1
14
+
15
+ ### Variables at render time
16
+
17
+ erb = RenderMePretty::Erb.new("/path/to/template.erb")
18
+ erb.render(a: 2)
19
+
20
+ Result: a: 2
21
+
22
+ ### Variables at both initialization and render time:
23
+
24
+ erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 3)
25
+ erb.render(a: "override", a: 4)
26
+
27
+ Result: a: 4
28
+
29
+ Variables at render time will override variables at initialization time.
30
+
31
+ ## Context Scope
32
+
33
+ If you want to use your own context object, pass it as a variable. The context variable is specially treated as a context object. Example:
34
+
35
+ person = Person.new # must implement get_binding
36
+ erb = RenderMePretty::Erb.new("/path/to/template.erb")
37
+ erb.render(context: person, a: 2)
38
+
39
+ The context will be `person`. So person methods and instance variables will be available in the ERB templates.
40
+
41
+ =end
42
+ require 'tilt/erb'
43
+
1
44
  module RenderMePretty
2
- class Context
3
- def initialize(hash={})
4
- # http://stackoverflow.com/questions/1338960/ruby-templates-how-to-pass-variables-into-inlined-erb
5
- hash.each do |key, value|
6
- instance_variable_set('@' + key.to_s, value)
7
- end
45
+ class Erb
46
+ def initialize(path, variables={})
47
+ @path = path
48
+ @init_vars = variables
49
+ @context = variables.delete(:context)
8
50
  end
9
51
 
10
- def override_variables!(vars)
11
- vars.each do |key, value|
12
- instance_variable_set('@' + key.to_s, value)
52
+ # Usage:
53
+ #
54
+ # render(context, a: 1, b: 2)
55
+ # render(a: 1, b: 2)
56
+ # render
57
+ def render(*args)
58
+ if args.last.is_a?(Hash)
59
+ render_vars = args.pop
60
+ @init_vars = @init_vars.merge(render_vars)
61
+ end
62
+ context = args[0]
63
+ context ||= @context || Object.new
64
+
65
+ context = context.clone # so we dont stomp the original object
66
+ # override context's instance variables with init and render vars.
67
+ @init_vars.each do |key, value|
68
+ context.instance_variable_set('@' + key.to_s, value)
69
+ end
70
+
71
+ template = Tilt::ERBTemplate.new(@path)
72
+ begin
73
+ template.render(context)
74
+ rescue Exception => e
75
+ handle_exception(e)
13
76
  end
14
77
  end
15
78
 
16
- def get_binding
17
- binding
79
+ # handles Tilt error
80
+ def handle_exception(e)
81
+ # first line of the baacktrace for Tilt has the line number
82
+ # spec/fixtures/invalid.erb:2:in `block in singleton class'
83
+ error_info = e.backtrace[0]
84
+ error_line_number = error_info.split(':')[1].to_i
85
+ pretty_error(e, error_line_number)
18
86
  end
19
87
 
20
- def self.load_helpers(base_folder)
21
- Dir.glob("#{base_folder}/**/*_helper.rb").each do |path|
22
- relative_path = path.sub("#{base_folder}/", "")
23
- class_name = File.basename(relative_path, '.rb').classify
88
+ def pretty_error(e, line)
89
+ pretty_path = @path.sub(/^\.\//, '')
90
+ io = StringIO.new
91
+ io.puts "#{e.class}: #{e.message}"
92
+ io.puts "Error evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{pretty_path}:"
24
93
 
25
- require path
26
- include const_get(class_name)
94
+ template = IO.read(@path)
95
+ template_lines = template.split("\n")
96
+ context = 5 # lines of context
97
+ top, bottom = [line-context-1, 0].max, line+context-1
98
+ spacing = template_lines.size.to_s.size
99
+ template_lines[top..bottom].each_with_index do |line_content, index|
100
+ line_number = top+index+1
101
+ if line_number == line
102
+ io.printf("%#{spacing}d %s\n".colorize(:red), line_number, line_content)
103
+ else
104
+ io.printf("%#{spacing}d %s\n", line_number, line_content)
105
+ end
27
106
  end
107
+
108
+ io.puts backtrace_lines(e)
109
+
110
+ if ENV['TEST']
111
+ io.string
112
+ else
113
+ puts io.string
114
+ exit 1
115
+ end
116
+ end
117
+
118
+ # Method produces a filtered original stack trace that can be appended to
119
+ # the pretty backtrace output.
120
+ #
121
+ # It parses the original backtrace that looks something like this:
122
+ #
123
+ # (erb):380:in `get_binding'
124
+ # /Users/tung/.rbenv/versions/2.5.0/lib/ruby/2.5.0/erb.rb:885:in `eval'
125
+ # /Users/tung/.rbenv/versions/2.5.0/lib/ruby/2.5.0/erb.rb:885:in `result'
126
+ # /Users/tung/src/tongueroo/lono/vendor/render_me_pretty/lib/render_me_pretty/erb.rb:67:in `render'
127
+ # /Users/tung/src/tongueroo/lono/vendor/render_me_pretty/lib/render_me_pretty.rb:11:in `result'
128
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/template.rb:32:in `build'
129
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/dsl.rb:82:in `block in build_templates'
130
+ # /Users/tung/src/tongueroo/lono/lib/lono/template/dsl.rb:81:in `each'
131
+ def backtrace_lines(e)
132
+ full = ENV['FULL_BACKTRACE']
133
+ if full
134
+ lines = e.backtrace
135
+ else
136
+ lines = e.backtrace
137
+ # filter out internal lines
138
+ removal_index = lines.find_index { |l| l =~ %r[lib/render_me_pretty] }
139
+ lines = lines[removal_index..-1] # remove leading lines above the lib/
140
+ # render_me_pretty lines by keeping lines past the removal index
141
+ lines.reject! { |l| l =~ %r[lib/render_me_pretty] } # now filter out
142
+ # render_me_pretty lines
143
+ lines = lines[0..7] # keep 8 lines
144
+ lines[0] = lines[0].colorize(:red)
145
+ end
146
+
147
+ # header
148
+ lines.unshift "\nOriginal filtered backtrace#{full ? '' : ' (last 8 lines)'}:"
149
+ # footer
150
+ lines << "\nRe-run with FULL_STACK_TRACE=1 to see all lines"
151
+ lines.join("\n")
28
152
  end
29
153
  end
30
154
  end
@@ -1,3 +1,3 @@
1
1
  module RenderMePretty
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "activesupport"
22
22
  spec.add_dependency "colorize"
23
+ spec.add_dependency "tilt"
23
24
 
24
25
  spec.add_development_dependency "bundler"
25
26
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: render_me_pretty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-13 00:00:00.000000000 Z
11
+ date: 2018-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tilt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -97,7 +111,6 @@ files:
97
111
  - bin/console
98
112
  - bin/setup
99
113
  - lib/render_me_pretty.rb
100
- - lib/render_me_pretty/context.rb
101
114
  - lib/render_me_pretty/erb.rb
102
115
  - lib/render_me_pretty/version.rb
103
116
  - render_me_pretty.gemspec
@@ -1,115 +0,0 @@
1
- require "active_support/core_ext/string"
2
- require "colorize"
3
-
4
- =begin
5
- ## Usage examples:
6
-
7
- Given an example template /path/to/template.erb that contains:
8
-
9
- a: <%= @a %>
10
-
11
- ### Variables at initialization
12
-
13
- erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 1)
14
- erb.render
15
-
16
- Result: a: 1
17
-
18
- ### Variables at render time
19
-
20
- erb = RenderMePretty::Erb.new("/path/to/template.erb")
21
- erb.render(a: 2)
22
-
23
- Result: a: 2
24
-
25
- ### Variables at both initialization and render time:
26
-
27
- erb = RenderMePretty::Erb.new("/path/to/template.erb", a: 3)
28
- erb.render(a: "override", a: 4)
29
-
30
- Result: a: 4
31
-
32
- Variables at render time will override variables at initialization time.
33
-
34
- ## Context Helpers
35
-
36
- When no context is provided, a built-in context object is created. You can add helpers to the built-in context object with:
37
-
38
- RenderMePretty::Context.load_helpers("lib/helpers")
39
-
40
- This loads modules defined in `lib/helpers` folder and adds their methods of the built-in context object. The helper classes must be defined with the following convetion: FooHelper and foo_helper.rb.
41
-
42
- Note, helpers will only work with the built-in context scope. If you are passing in your own context object to be used, then you should handle adding helper methods to that context object yourself.
43
-
44
- ## Custom Context Scope
45
-
46
- A built-in context object is provided for convenience. If you want to use your own context object, pass it as a variable. The context variable is specially treated as a context object. Example:
47
-
48
- person = Person.new # must implement get_binding
49
- erb = RenderMePretty::Erb.new("/path/to/template.erb")
50
- erb.render(context: person, a: 2)
51
-
52
- The context will be `person`. So person methods and instance variables will be available in the ERB templates.
53
-
54
- =end
55
- module RenderMePretty
56
- class Erb
57
- def initialize(path, variables={})
58
- @path = path
59
- @variables = variables
60
- if variables[:context]
61
- @context = variables.delete(:context)
62
- else
63
- @context = Context.new(variables)
64
- end
65
- end
66
-
67
- def render(override_vars={})
68
- @context.override_variables!(override_vars)
69
- template = IO.read(@path)
70
- ERB.new(template, nil, "-").result(@context.get_binding)
71
- rescue Exception => e
72
- handle_exception(e)
73
- end
74
-
75
- # How to know where ERB stopped? - https://www.ruby-forum.com/topic/182051
76
- # syntax errors have the (erb):xxx info in e.message
77
- # undefined variables have (erb):xxx info in e.backtrace
78
- def handle_exception(e)
79
- error_info = e.message.split("\n").grep(/\(erb\)/)[0]
80
- error_info ||= e.backtrace.grep(/\(erb\)/)[0]
81
- raise unless error_info # unable to find the (erb):xxx: error line
82
-
83
- line = error_info.split(':')[1].to_i
84
- io = StringIO.new
85
- io.puts "#{e.class} evaluating ERB template on line #{line.to_s.colorize(:red)} of: #{@path.sub(/^\.\//, '')}"
86
-
87
- template = IO.read(@path)
88
- template_lines = template.split("\n")
89
- context = 5 # lines of context
90
- top, bottom = [line-context-1, 0].max, line+context-1
91
- spacing = template_lines.size.to_s.size
92
- template_lines[top..bottom].each_with_index do |line_content, index|
93
- line_number = top+index+1
94
- if line_number == line
95
- io.printf("%#{spacing}d %s\n".colorize(:red), line_number, line_content)
96
- else
97
- io.printf("%#{spacing}d %s\n", line_number, line_content)
98
- end
99
- end
100
-
101
- # Append the original stack trace also
102
- io.puts("\nOriginal backtrace (last 5 lines):")
103
- lines = ENV['FULL_STACK_TRACE'] ? e.backtrace : e.backtrace[0..4]
104
- io.write(lines.join("\n"))
105
- io.puts("\nRe-run with FULL_STACK_TRACE=1 to see all lines")
106
-
107
- if ENV['TEST']
108
- io.string
109
- else
110
- puts io.string
111
- exit 1
112
- end
113
- end
114
- end
115
- end