rembrandt 0.0.3 → 0.1.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 +29 -1
- data/lib/rembrandt/config.rb +39 -0
- data/lib/rembrandt/engines/pygments_known_languages.rb +9 -0
- data/lib/rembrandt/engines/web_service.rb +1 -0
- data/lib/rembrandt/formatters/formatted_code.rb +21 -0
- data/lib/rembrandt/formatters/table.rb +10 -0
- data/lib/rembrandt/formatters/templates/table.erb +24 -0
- data/lib/rembrandt/highlighter.rb +52 -6
- data/lib/rembrandt/language_normalizer.rb +29 -0
- data/lib/rembrandt/stores/fetchable.rb +18 -0
- data/lib/rembrandt/stores/file.rb +51 -0
- data/lib/rembrandt/stores/redis.rb +33 -0
- data/lib/rembrandt/version.rb +1 -1
- data/rembrandt.gemspec +3 -0
- data/test/rembrandt/formatters/formatted_code_test.rb +16 -0
- data/test/rembrandt/formatters/table_test.rb +27 -3
- data/test/rembrandt/highlighter_test.rb +45 -12
- data/test/rembrandt/language_normalizer_test.rb +22 -0
- data/test/rembrandt/stores/file_test.rb +45 -0
- data/test/rembrandt/stores/redis_test.rb +67 -0
- data/test/support/ruby_sample_2.rb +3 -0
- data/test/support/ruby_sample_2.rb.html +4 -0
- data/test/support/ruby_sample_2.rb.tableized.html +28 -0
- metadata +53 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4e5b88327738db6739926a9ac97b9b9d6fb2ac6
|
4
|
+
data.tar.gz: 80181d4b01d282d0323ba3cd54e0a861f47f6760
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad2e5d4336e996780f08aa5bd9eb0065add68477d71fad5a3de3227259ff4659fab4d11a0545f9848f623aae64935b50b3fe8ad7a323df54e138521dccc1732c
|
7
|
+
data.tar.gz: ca01834cba775497338a4e1b56b781f15aeefdfe2cd8c54f66139db81b639f6237e1c5f6fc0f4684dc0bfefa0429ff7a46ad176ab94984c1b5c1517de993f034
|
data/README.md
CHANGED
@@ -18,7 +18,31 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
### Basic Highlighting
|
22
|
+
|
23
|
+
```irb
|
24
|
+
> require 'rembrandt'
|
25
|
+
> highlighter = Rembrandt::Highlighter.new
|
26
|
+
> highlighter.highlight("class Sample\nend", "ruby")
|
27
|
+
```
|
28
|
+
|
29
|
+
### Highlighting Source in a File
|
30
|
+
|
31
|
+
```irb
|
32
|
+
> require 'rembrandt'
|
33
|
+
> highlighter = Rembrandt::Highlighter.new
|
34
|
+
> highlighter.highlight_file("./my_input_file.rb", "ruby")
|
35
|
+
```
|
36
|
+
|
37
|
+
### Using a Formatter
|
38
|
+
|
39
|
+
```irb
|
40
|
+
> require 'rembrandt'
|
41
|
+
> highlighter = Rembrandt::Highlighter.new
|
42
|
+
> formatter = Rembrandt::Formatters::Table.new
|
43
|
+
> code = highlighter.highlight("class Sample\nend", "ruby")
|
44
|
+
> table = formatter.format(code, "ruby")
|
45
|
+
```
|
22
46
|
|
23
47
|
## Contributing
|
24
48
|
|
@@ -27,3 +51,7 @@ TODO: Write usage instructions here
|
|
27
51
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
52
|
4. Push to the branch (`git push origin my-new-feature`)
|
29
53
|
5. Create new Pull Request
|
54
|
+
|
55
|
+
### When Developing
|
56
|
+
|
57
|
+
It's expected that when developing that you have both Redis and Python/Pygmentize available on your machine. If you don't have Pygments installed, Rembrant's tests will try to use the HTTP highlight engine which is blocked by VCR.
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Rembrandt
|
2
|
+
class Config
|
3
|
+
def self.default_language=(input)
|
4
|
+
@default_language = input
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.default_language
|
8
|
+
@default_language ||= library_default_language
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.library_default_language
|
12
|
+
"ruby"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.engine_priority=(engines)
|
16
|
+
@engine_priority = engines
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.engine_priority
|
20
|
+
@engine_priority ||= library_default_engine_priority
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.library_default_engine_priority
|
24
|
+
[Engines::Pygmentize, Engines::WebService]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.file_store_directory
|
28
|
+
@file_store_directory ||= library_default_file_store_directory
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.library_default_file_store_directory
|
32
|
+
'./tmp/.rembrandt_cache'
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.file_store_directory=(input)
|
36
|
+
@file_store_directory = input
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Rembrandt
|
2
|
+
module Engines
|
3
|
+
module PygmentsKnownLanguages
|
4
|
+
def known_languages
|
5
|
+
['sourceslist', 'sources.list', 'delphi', 'pas', 'pascal', 'objectpascal', 'js+mako', 'javascript+mako', 'iex', 'psql', 'postgresql-console', 'postgres-console', 'brainfuck', 'bf', 'ceylon', 'js+django', 'javascript+django', 'js+jinja', 'javascript+jinja', 'html+evoque', 'numpy', 'modula2', 'm2', 'live-script', 'livescript', 'nimrod', 'nim', 'bash', 'sh', 'ksh', 'html+django', 'html+jinja', 'css+php', 'xml+lasso', 'vim', 'css+genshitext', 'css+genshi', 'fancy', 'fy', 'cfm', 'cfs', 'ssp', 'smarty', 'xml+evoque', 'hx', 'haXe', 'powershell', 'posh', 'ps1', 'tea', 'html+cheetah', 'html+spitfire', 'rbcon', 'irb', 'mason', 'django', 'jinja', 'jags', 'apacheconf', 'aconf', 'apache', 'dtd', 'dylan-console', 'dylan-repl', 'lighty', 'lighttpd', 'java', 'js+genshitext', 'js+genshi', 'javascript+genshitext', 'javascript+genshi', 'scheme', 'scm', 'nemerle', 'rhtml', 'html+erb', 'html+ruby', 'ragel-java', 'dpatch', 'puppet', 'octave', 'coffee-script', 'coffeescript', 'ragel-d', 'scilab', 'monkey', 'html+myghty', 'erl', 'css', 'js+smarty', 'javascript+smarty', 'io', 'cobolfree', 'asy', 'asymptote', 'vhdl', 'python3', 'py3', 'css+erb', 'css+ruby', 'fortran', 'd-objdump', 'mysql', 'rebol', 'cpp', 'c++', 'erb', 'cbmbas', 'befunge', 'julia', 'jl', 'moon', 'moonscript', 'rb', 'ruby', 'duby', 'xml+smarty', 'dylan', 'groovy', 'trac-wiki', 'moin', 'ahk', 'c', 'html', 'felix', 'flx', 'cmake', 'nsis', 'nsi', 'nsh', 'sp', 'mako', 'vgl', 'velocity', 'koka', 'cuda', 'cu', 'gnuplot', 'irc', 'prolog', 'python', 'py', 'sage', 'css+django', 'css+jinja', 'verilog', 'v', 'smalltalk', 'squeak', 'js+myghty', 'javascript+myghty', 'yaml', 'antlr-as', 'antlr-actionscript', 'xml+mako', 'xslt', 'urbiscript', 'scaml', 'SCAML', 'splus', 's', 'r', 'dylan-lid', 'lid', 'maql', 'sqlite3', 'boo', 'ocaml', 'ec', 'as', 'actionscript', 'vb.net', 'vbnet', 'squidconf', 'squid.conf', 'squid', 'xquery', 'xqy', 'xq', 'xql', 'xqm', 'd', 'fan', 'pot', 'po', 'logos', 'jlcon', 'lasso', 'lassoscript', 'scss', 'bbcode', 'haml', 'HAML', 'Clipper', 'XBase', 'py3tb', 'mupad', 'xml+erb', 'xml+ruby', 'dart', 'idl', 'dg', 'evoque', 'jade', 'JADE', 'c-objdump', 'kconfig', 'menuconfig', 'linux-config', 'kernel-config', 'jsp', 'registry', 'abap', 'xml+velocity', 'js+cheetah', 'javascript+cheetah', 'js+spitfire', 'javascript+spitfire', 'html+mako', 'ragel-ruby', 'ragel-rb', 'RobotFramework', 'robotframework', 'protobuf', 'cfengine3', 'cf3', 'ragel', 'glsl', 'cobol', 'ts', 'ada', 'ada95ada2005', 'postgresql', 'postgres', 'xtend', 'logtalk', 'objdump', 'css+mako', 'ca65', 'objective-c++', 'objectivec++', 'obj-c++', 'objc++', 'Cucumber', 'cucumber', 'Gherkin', 'gherkin', 'html+php', 'make', 'makefile', 'mf', 'bsdmake', 'postscript', 'haxeml', 'hxml', 'kotlin', 'plpgsql', 'vala', 'vapi', 'haskell', 'hs', 'bro', 'lua', 'pov', 'sass', 'SASS', 'antlr-java', 'tcl', 'antlr-objc', 'js+erb', 'javascript+erb', 'js+ruby', 'javascript+ruby', 'racket', 'rkt', 'aspectj', 'basemake', 'antlr-python', 'cpp-objdump', 'c++-objdumb', 'cxx-objdump', 'genshitext', 'ioke', 'ik', 'pypylog', 'pypy', 'croc', 'objective-j', 'objectivej', 'obj-j', 'objj', 'gas', 'bat', 'snobol', 'pycon', 'xml', 'antlr', 'opa', 'xml+cheetah', 'xml+spitfire', 'go', 'diff', 'udiff', 'minid', 'cython', 'pyx', 'ragel-c', 'erlang', 'control', 'aspx-vb', 'bugs', 'winbugs', 'openbugs', 'ragel-cpp', 'aspx-cs', 'matlabsession', 'properties', 'groff', 'nroff', 'man', 'clojure', 'clj', 'modelica', 'qml', 'Qt Meta Language', 'Qt modeling Language', 'js+lasso', 'javascript+lasso', 'antlr-perl', 'genshi', 'kid', 'xml+genshi', 'xml+kid', 'blitzmax', 'bmax', 'treetop', 'matlab', 'myghty', 'html+genshi', 'html+kid', 'duel', 'Duel Engine', 'Duel View', 'JBST', 'jbst', 'JsonML+BST', 'perl', 'pl', 'fsharp', 'rst', 'rest', 'restructuredtext', 'newlisp', 'scala', 'css+lasso', 'xml+php', 'stan', 'ini', 'cfg', 'moocode', 'shell-session', 'spec', 'newspeak', 'console', 'coq', 'raw', 'tcsh', 'csh', 'html+lasso', 'csharp', 'c#', 'gst', 'rconsole', 'rout', 'mxml', 'tex', 'latex', 'css+smarty', 'text', 'antlr-csharp', 'antlr-c#', 'openedge', 'abl', 'progress', 'cheetah', 'spitfire', 'smali', 'css+myghty', 'rd', 'llvm', 'sml', 'elixir', 'ex', 'exs', 'nginx', 'gooddata-cl', 'applescript', 'html+smarty', 'objective-c', 'objectivec', 'obj-c', 'objc', 'js', 'javascript', 'rust', 'common-lisp', 'cl', 'ragel-em', 'as3', 'actionscript3', 'systemverilog', 'sv', 'lhs', 'literate-haskell', 'pytb', 'php', 'php3', 'php4', 'php5', 'antlr-cpp', 'gosu', 'hybris', 'hy', 'js+php', 'javascript+php', 'factor', 'html+velocity', 'mscgen', 'msc', 'ooc', 'sql', 'http', 'ecl', 'redcode', 'ragel-objc', 'xml+django', 'xml+jinja', 'awk', 'gawk', 'mawk', 'nawk', 'json', 'nasm', 'antlr-ruby', 'antlr-rb', 'xml+myghty', 'autoit', 'Autoit']
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Rembrandt
|
2
|
+
module Formatters
|
3
|
+
class FormattedCode
|
4
|
+
attr_reader :code, :language
|
5
|
+
|
6
|
+
def initialize(input_code, input_language)
|
7
|
+
@code = extract_code_from_html(input_code)
|
8
|
+
@language = input_language
|
9
|
+
end
|
10
|
+
|
11
|
+
def line_count
|
12
|
+
code.lines.count
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract_code_from_html(input)
|
16
|
+
matches = input.match(/<pre>(.+)<\/pre>/m)
|
17
|
+
matches[1] if matches
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,7 +1,17 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'tilt'
|
3
|
+
require_relative 'formatted_code'
|
4
|
+
|
1
5
|
module Rembrandt
|
2
6
|
module Formatters
|
3
7
|
class Table
|
8
|
+
def format(input_code, input_language)
|
9
|
+
template.render FormattedCode.new(input_code, input_language)
|
10
|
+
end
|
4
11
|
|
12
|
+
def template
|
13
|
+
@template ||= Tilt.new('./lib/rembrandt/formatters/templates/table.erb', :trim => true)
|
14
|
+
end
|
5
15
|
end
|
6
16
|
end
|
7
17
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div class="highlight">
|
2
|
+
<table>
|
3
|
+
<tr>
|
4
|
+
<td class="gutter">
|
5
|
+
<pre class="line-numbers">
|
6
|
+
<% line_count.times do |i| %>
|
7
|
+
<span class='line-number'><%= i + 1 %></span>
|
8
|
+
<% end %>
|
9
|
+
</pre>
|
10
|
+
</td>
|
11
|
+
<td class='code'>
|
12
|
+
<pre>
|
13
|
+
<code class='<%= language %>'>
|
14
|
+
<% code.lines.each do |line| %>
|
15
|
+
<span class='line'>
|
16
|
+
<%= line %>
|
17
|
+
</span>
|
18
|
+
<% end %>
|
19
|
+
</code>
|
20
|
+
</pre>
|
21
|
+
</td>
|
22
|
+
</tr>
|
23
|
+
</table>
|
24
|
+
</div>
|
@@ -1,23 +1,69 @@
|
|
1
1
|
require_relative 'engines/pygmentize'
|
2
|
+
require_relative 'engines/web_service'
|
3
|
+
require_relative 'stores/file'
|
4
|
+
require_relative 'stores/redis'
|
5
|
+
require_relative 'config'
|
6
|
+
require_relative 'language_normalizer'
|
2
7
|
|
3
8
|
module Rembrandt
|
4
9
|
class Highlighter
|
5
|
-
|
10
|
+
attr_writer :store
|
6
11
|
|
7
12
|
def initialize(input_engine = nil)
|
8
|
-
@engine =
|
13
|
+
@engine = input_engine.new if input_engine
|
14
|
+
end
|
15
|
+
|
16
|
+
def engine
|
17
|
+
@engine ||= autoselect_engine
|
18
|
+
end
|
19
|
+
|
20
|
+
def store
|
21
|
+
@store ||= autoselect_store
|
9
22
|
end
|
10
23
|
|
11
24
|
def default_language
|
12
|
-
|
25
|
+
Config.default_language
|
26
|
+
end
|
27
|
+
|
28
|
+
def autoselect_store
|
29
|
+
redis = Stores::Redis.new
|
30
|
+
if redis.available?
|
31
|
+
redis
|
32
|
+
else
|
33
|
+
Stores::File.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def engines
|
38
|
+
Config.engine_priority
|
13
39
|
end
|
14
40
|
|
15
41
|
def autoselect_engine
|
16
|
-
|
42
|
+
begin
|
43
|
+
engines.detect(&:available?).new
|
44
|
+
rescue
|
45
|
+
raise "Error: no highlight engine is available."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def highlight(input, input_language = default_language)
|
50
|
+
language = normalize_language(input_language)
|
51
|
+
store.fetch(input, language) do
|
52
|
+
engine.highlight(input, language)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def highlight_file(filename, language = default_language)
|
57
|
+
data = File.read(filename)
|
58
|
+
highlight(data, language)
|
59
|
+
end
|
60
|
+
|
61
|
+
def normalize_language(input)
|
62
|
+
language_normalizer.process(input)
|
17
63
|
end
|
18
64
|
|
19
|
-
def
|
20
|
-
|
65
|
+
def language_normalizer
|
66
|
+
@language_normalizer ||= LanguageNormalizer.new
|
21
67
|
end
|
22
68
|
end
|
23
69
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'engines/pygments_known_languages'
|
2
|
+
|
3
|
+
module Rembrandt
|
4
|
+
class LanguageNormalizer
|
5
|
+
include Engines::PygmentsKnownLanguages
|
6
|
+
|
7
|
+
def known_language?(input)
|
8
|
+
known_languages.detect{|lang| lang == input}
|
9
|
+
end
|
10
|
+
|
11
|
+
def known_variant?(input)
|
12
|
+
known_variants[input]
|
13
|
+
end
|
14
|
+
|
15
|
+
def known_variants
|
16
|
+
{'ru' => 'ruby',
|
17
|
+
'm' => 'objc',
|
18
|
+
'yml' => 'yaml'}
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(input)
|
22
|
+
known_language?(input) || known_variant?(input) || raise_exception(input)
|
23
|
+
end
|
24
|
+
|
25
|
+
def raise_exception(input)
|
26
|
+
raise ArgumentError.new("Unknown language specifier: #{input}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rembrandt
|
2
|
+
module Stores
|
3
|
+
module Fetchable
|
4
|
+
def key_for(input, language)
|
5
|
+
Digest::MD5.hexdigest(input + language)
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(input, language)
|
9
|
+
result = read key_for(input, language)
|
10
|
+
if result.nil? && block_given?
|
11
|
+
data_to_store = yield
|
12
|
+
write(key_for(input, language), data_to_store)
|
13
|
+
return data_to_store
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'digest/md5'
|
3
|
+
require_relative 'fetchable'
|
4
|
+
|
5
|
+
module Rembrandt
|
6
|
+
module Stores
|
7
|
+
class File
|
8
|
+
include Fetchable
|
9
|
+
attr_reader :output_directory
|
10
|
+
|
11
|
+
def initialize(directory = nil)
|
12
|
+
self.output_directory = directory || Config.file_store_directory
|
13
|
+
create_directory
|
14
|
+
end
|
15
|
+
|
16
|
+
def output_directory=(name)
|
17
|
+
name += '/' unless name.end_with?('/')
|
18
|
+
@output_directory = name
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_directory
|
22
|
+
FileUtils.mkdir_p output_directory
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(key, data)
|
26
|
+
::File.open( filename_for(key), "w" ) do |f|
|
27
|
+
f.write(data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def read(key)
|
32
|
+
filename = filename_for(key)
|
33
|
+
if ::File.exist?(filename)
|
34
|
+
::File.read(filename_for(key))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def filename_for(key)
|
39
|
+
output_directory + prefix + key
|
40
|
+
end
|
41
|
+
|
42
|
+
def prefix
|
43
|
+
'rembrandt_'
|
44
|
+
end
|
45
|
+
|
46
|
+
def flush
|
47
|
+
`rm -rf #{output_directory}/*` if Dir.exist?(output_directory)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'redis'
|
3
|
+
require_relative 'fetchable'
|
4
|
+
|
5
|
+
module Rembrandt
|
6
|
+
module Stores
|
7
|
+
class Redis
|
8
|
+
include Fetchable
|
9
|
+
attr_reader :database, :url
|
10
|
+
|
11
|
+
def initialize(url = nil)
|
12
|
+
@url = ENV['REMBRANDT_REDIS_URL']
|
13
|
+
@database = ::Redis.new(:url => url)
|
14
|
+
end
|
15
|
+
|
16
|
+
def available?
|
17
|
+
defined?(::Redis)
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(key, data)
|
21
|
+
database.set(key, data)
|
22
|
+
end
|
23
|
+
|
24
|
+
def read(key)
|
25
|
+
database.get(key)
|
26
|
+
end
|
27
|
+
|
28
|
+
def flush
|
29
|
+
database.flushdb
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/rembrandt/version.rb
CHANGED
data/rembrandt.gemspec
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
require './lib/rembrandt/formatters/formatted_code'
|
3
|
+
|
4
|
+
class FormattedCodeTest < CodeHighlightTest
|
5
|
+
def test_it_counts_lines
|
6
|
+
input = File.read('./test/support/ruby_sample_1.rb.html')
|
7
|
+
code = Rembrandt::Formatters::FormattedCode.new(input, 'ruby')
|
8
|
+
assert_equal 5, code.line_count
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_it_stores_the_language
|
12
|
+
input = File.read('./test/support/python_sample_1.py.html')
|
13
|
+
code = Rembrandt::Formatters::FormattedCode.new("", 'python')
|
14
|
+
assert_equal 'python', code.language
|
15
|
+
end
|
16
|
+
end
|
@@ -1,9 +1,33 @@
|
|
1
|
-
require '
|
2
|
-
require 'minitest/pride'
|
1
|
+
require './test/test_helper'
|
3
2
|
require './lib/rembrandt/formatters/table'
|
4
3
|
|
5
|
-
class FormattersTableTest <
|
4
|
+
class FormattersTableTest < CodeHighlightTest
|
5
|
+
attr_reader :formatter
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@formatter = Rembrandt::Formatters::Table.new
|
9
|
+
end
|
10
|
+
|
6
11
|
def test_it_exists
|
7
12
|
assert Rembrandt::Formatters::Table.new
|
8
13
|
end
|
14
|
+
|
15
|
+
def test_it_tableizes
|
16
|
+
input = File.read('./test/support/ruby_sample_2.rb.html')
|
17
|
+
expected = File.read('./test/support/ruby_sample_2.rb.tableized.html')
|
18
|
+
#expected_doc = Nokogiri::HTML(expected)
|
19
|
+
output = formatter.format(input, 'ruby')
|
20
|
+
#output_doc = Nokogiri::HTML(output)
|
21
|
+
|
22
|
+
#assert (expected_doc == output_doc), html_diff(expected_doc, output_doc)
|
23
|
+
assert_equal expected, output
|
24
|
+
end
|
25
|
+
|
26
|
+
def html_diff(doc_1, doc_2)
|
27
|
+
doc_1.diff(doc_2).collect do |change,node|
|
28
|
+
if ["+", "-"].include?(change)
|
29
|
+
"#{change} #{node.to_html}".ljust(30) + node.parent.path
|
30
|
+
end
|
31
|
+
end.reject!(&:nil?).join("\n")
|
32
|
+
end
|
9
33
|
end
|
@@ -17,7 +17,8 @@ class HighlighterTest < CodeHighlightTest
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_highlight_takes_an_input_and_a_language
|
20
|
-
|
20
|
+
result = highlighter.highlight("Hello, World", 'ruby')
|
21
|
+
assert result, "Got: #{result}"
|
21
22
|
end
|
22
23
|
|
23
24
|
def test_highlight_properly_highlights_ruby
|
@@ -28,6 +29,16 @@ class HighlighterTest < CodeHighlightTest
|
|
28
29
|
assert_highlight 'python_sample_1.py', 'python'
|
29
30
|
end
|
30
31
|
|
32
|
+
def test_it_highlights_a_file_directly
|
33
|
+
input_filename = './test/support/ruby_sample_1.rb'
|
34
|
+
expected = File.read('./test/support/ruby_sample_1.rb.html')
|
35
|
+
assert_equal expected, highlighter.highlight_file(input_filename, 'ruby')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_it_normalizes_unusual_language_abbreviations
|
39
|
+
assert_highlight 'ruby_sample_1.rb', 'ru'
|
40
|
+
end
|
41
|
+
|
31
42
|
class StubEngine
|
32
43
|
def highlight(text, language)
|
33
44
|
"stub highlight"
|
@@ -39,18 +50,40 @@ class HighlighterTest < CodeHighlightTest
|
|
39
50
|
assert_equal "stub highlight", stubbed_highlighter.highlight("hello", "ruby")
|
40
51
|
end
|
41
52
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
53
|
+
class StubStore
|
54
|
+
def write(key, data)
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def fetch(input, language)
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def flush
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_it_uses_a_datastore
|
68
|
+
lighter = Rembrandt::Highlighter.new(StubEngine)
|
69
|
+
store = StubStore.new
|
70
|
+
highlighter.store = store
|
71
|
+
store.expects(:fetch).once
|
72
|
+
highlighter.highlight("Hello, World")
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_it_uses_the_default_language_from_config
|
76
|
+
Rembrandt::Config.default_language = "python"
|
77
|
+
assert_equal "python", highlighter.default_language
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_it_uses_the_engine_prioritization_from_config
|
81
|
+
preferred = [Rembrandt::Engines::Pygmentize]
|
82
|
+
Rembrandt::Config.engine_priority = preferred
|
83
|
+
assert_equal preferred, highlighter.engines
|
47
84
|
end
|
48
85
|
|
49
|
-
def
|
50
|
-
|
51
|
-
Rembrandt::Engines::WebService.stubs(:available?).returns(true)
|
52
|
-
expected_engine = Rembrandt::Engines::WebService
|
53
|
-
lighter = Rembrandt::Highlighter.new
|
54
|
-
assert_equal expected_engine, lighter.engine.class
|
86
|
+
def teardown
|
87
|
+
highlighter.store.flush
|
55
88
|
end
|
56
89
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
require './lib/rembrandt/language_normalizer'
|
3
|
+
|
4
|
+
class LanguageNormalizerTest < CodeHighlightTest
|
5
|
+
attr_reader :normalizer
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@normalizer = Rembrandt::LanguageNormalizer.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_it_processes_a_known_variant
|
12
|
+
assert_equal 'ruby', normalizer.process('ru')
|
13
|
+
assert_equal 'objc', normalizer.process('m')
|
14
|
+
assert_equal 'yaml', normalizer.process('yml')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_it_cannot_process_an_unknown_language
|
18
|
+
assert_raises(ArgumentError){
|
19
|
+
normalizer.process('asdf')
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
require './lib/rembrandt/stores/file'
|
3
|
+
require './lib/rembrandt/config'
|
4
|
+
|
5
|
+
class StoresFileTest < CodeHighlightTest
|
6
|
+
attr_reader :store
|
7
|
+
|
8
|
+
def target
|
9
|
+
Rembrandt::Config.file_store_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@store = Rembrandt::Stores::File.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_it_creates_the_storage_folder
|
17
|
+
`rm -rf #{target}` if Dir.exist?(target)
|
18
|
+
refute Dir.exist?(target), "Directory #{target} should not exist."
|
19
|
+
store = Rembrandt::Stores::File.new(target)
|
20
|
+
assert Dir.exist?(target), "Directory #{target} should exist."
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_it_fetches_data_from_a_file
|
24
|
+
sample = "Hello, World!"
|
25
|
+
key = "001"
|
26
|
+
store.write(key, sample)
|
27
|
+
fetched = store.read(key)
|
28
|
+
assert_equal sample, fetched
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_it_calculates_keys
|
32
|
+
sample = "Hello, World!"
|
33
|
+
assert store.key_for(sample, 'ruby')
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_it_uses_the_configured_output_directory
|
37
|
+
Rembrandt::Config.file_store_directory = './tmp/'
|
38
|
+
store2 = Rembrandt::Stores::File.new
|
39
|
+
assert_equal './tmp/', store2.output_directory
|
40
|
+
end
|
41
|
+
|
42
|
+
def teardown
|
43
|
+
store.flush
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
require './lib/rembrandt/stores/redis'
|
3
|
+
|
4
|
+
class StoresRedisTest < CodeHighlightTest
|
5
|
+
attr_reader :store
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@store = Rembrandt::Stores::Redis.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_it_is_not_available_when_redis_is_not_loaded
|
12
|
+
Object.const_set('REAL_REDIS', Redis)
|
13
|
+
Object.send(:remove_const, :Redis)
|
14
|
+
refute store.available?
|
15
|
+
Object.const_set('Redis', REAL_REDIS)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_it_is_available_when_redis_is_loaded
|
19
|
+
assert store.available?, "Redis should be available when required"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_it_fetches_data
|
23
|
+
sample = "Hello, World!"
|
24
|
+
key = "001"
|
25
|
+
store.write(key, sample)
|
26
|
+
fetched = store.read(key)
|
27
|
+
assert_equal sample, fetched
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_it_calculates_keys
|
31
|
+
sample = "Hello, World!"
|
32
|
+
assert store.key_for(sample, 'ruby')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_it_flushes_the_database
|
36
|
+
store.write("002", "Hello")
|
37
|
+
assert store.read("002")
|
38
|
+
store.flush
|
39
|
+
refute store.read("002"), "All keys should be gone"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_fetch_does_not_write_when_there_is_no_block
|
43
|
+
refute store.fetch("hello", "ruby"), "hello should not be found"
|
44
|
+
key = store.key_for("hello", "ruby")
|
45
|
+
refute store.read(key), "hello should not have been written"
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_fetch_writes_the_result_of_a_block
|
49
|
+
refute store.fetch("hello", "ruby")
|
50
|
+
result = store.fetch("hello", "ruby"){ "Hello, World" }
|
51
|
+
assert_equal "Hello, World", result
|
52
|
+
key = store.key_for("hello", "ruby")
|
53
|
+
assert_equal result, store.read(key)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_it_uses_a_redis_url_in_an_environment_variable
|
57
|
+
url = "redis://redisuser:redispassword@provider.example.com:9352/"
|
58
|
+
ENV['REMBRANDT_REDIS_URL'] = url
|
59
|
+
store2 = Rembrandt::Stores::Redis.new
|
60
|
+
assert_equal url, store2.url
|
61
|
+
ENV['REMBRANDT_REDIS_URL'] = ''
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
store.flush
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<div class="highlight"><pre><span class="ss">Blogger</span><span class="p">:</span><span class="ss">:Application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
|
2
|
+
<span class="n">resources</span> <span class="ss">:articles</span>
|
3
|
+
<span class="k">end</span>
|
4
|
+
</pre></div>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="highlight">
|
2
|
+
<table>
|
3
|
+
<tr>
|
4
|
+
<td class="gutter">
|
5
|
+
<pre class="line-numbers">
|
6
|
+
<span class='line-number'>1</span>
|
7
|
+
<span class='line-number'>2</span>
|
8
|
+
<span class='line-number'>3</span>
|
9
|
+
</pre>
|
10
|
+
</td>
|
11
|
+
<td class='code'>
|
12
|
+
<pre>
|
13
|
+
<code class='ruby'>
|
14
|
+
<span class='line'>
|
15
|
+
<span class="ss">Blogger</span><span class="p">:</span><span class="ss">:Application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
|
16
|
+
</span>
|
17
|
+
<span class='line'>
|
18
|
+
<span class="n">resources</span> <span class="ss">:articles</span>
|
19
|
+
</span>
|
20
|
+
<span class='line'>
|
21
|
+
<span class="k">end</span>
|
22
|
+
</span>
|
23
|
+
</code>
|
24
|
+
</pre>
|
25
|
+
</td>
|
26
|
+
</tr>
|
27
|
+
</table>
|
28
|
+
</div>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rembrandt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Casimir
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,34 @@ dependencies:
|
|
108
108
|
- - '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: redis
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: tilt
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
description: A library for generating and storing syntax-highlighted code
|
112
140
|
email:
|
113
141
|
- jeff@casimircreative.com
|
@@ -122,20 +150,35 @@ files:
|
|
122
150
|
- README.md
|
123
151
|
- Rakefile
|
124
152
|
- lib/rembrandt.rb
|
153
|
+
- lib/rembrandt/config.rb
|
125
154
|
- lib/rembrandt/engines/pygmentize.rb
|
155
|
+
- lib/rembrandt/engines/pygments_known_languages.rb
|
126
156
|
- lib/rembrandt/engines/web_service.rb
|
157
|
+
- lib/rembrandt/formatters/formatted_code.rb
|
127
158
|
- lib/rembrandt/formatters/table.rb
|
159
|
+
- lib/rembrandt/formatters/templates/table.erb
|
128
160
|
- lib/rembrandt/highlighter.rb
|
161
|
+
- lib/rembrandt/language_normalizer.rb
|
162
|
+
- lib/rembrandt/stores/fetchable.rb
|
163
|
+
- lib/rembrandt/stores/file.rb
|
164
|
+
- lib/rembrandt/stores/redis.rb
|
129
165
|
- lib/rembrandt/version.rb
|
130
166
|
- rembrandt.gemspec
|
131
167
|
- test/rembrandt/engines/pygmentize_test.rb
|
132
168
|
- test/rembrandt/engines/web_service_test.rb
|
169
|
+
- test/rembrandt/formatters/formatted_code_test.rb
|
133
170
|
- test/rembrandt/formatters/table_test.rb
|
134
171
|
- test/rembrandt/highlighter_test.rb
|
172
|
+
- test/rembrandt/language_normalizer_test.rb
|
173
|
+
- test/rembrandt/stores/file_test.rb
|
174
|
+
- test/rembrandt/stores/redis_test.rb
|
135
175
|
- test/support/python_sample_1.py
|
136
176
|
- test/support/python_sample_1.py.html
|
137
177
|
- test/support/ruby_sample_1.rb
|
138
178
|
- test/support/ruby_sample_1.rb.html
|
179
|
+
- test/support/ruby_sample_2.rb
|
180
|
+
- test/support/ruby_sample_2.rb.html
|
181
|
+
- test/support/ruby_sample_2.rb.tableized.html
|
139
182
|
- test/support/vcr_cassettes/web_engine_highlights_ruby_sample_1.yml
|
140
183
|
- test/support/vcr_cassettes/web_engine_is_accessible.yml
|
141
184
|
- test/test_helper.rb
|
@@ -159,19 +202,26 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
202
|
version: '0'
|
160
203
|
requirements: []
|
161
204
|
rubyforge_project:
|
162
|
-
rubygems_version: 2.
|
205
|
+
rubygems_version: 2.0.6
|
163
206
|
signing_key:
|
164
207
|
specification_version: 4
|
165
208
|
summary: Powered by the amazing Pygments Python library.
|
166
209
|
test_files:
|
167
210
|
- test/rembrandt/engines/pygmentize_test.rb
|
168
211
|
- test/rembrandt/engines/web_service_test.rb
|
212
|
+
- test/rembrandt/formatters/formatted_code_test.rb
|
169
213
|
- test/rembrandt/formatters/table_test.rb
|
170
214
|
- test/rembrandt/highlighter_test.rb
|
215
|
+
- test/rembrandt/language_normalizer_test.rb
|
216
|
+
- test/rembrandt/stores/file_test.rb
|
217
|
+
- test/rembrandt/stores/redis_test.rb
|
171
218
|
- test/support/python_sample_1.py
|
172
219
|
- test/support/python_sample_1.py.html
|
173
220
|
- test/support/ruby_sample_1.rb
|
174
221
|
- test/support/ruby_sample_1.rb.html
|
222
|
+
- test/support/ruby_sample_2.rb
|
223
|
+
- test/support/ruby_sample_2.rb.html
|
224
|
+
- test/support/ruby_sample_2.rb.tableized.html
|
175
225
|
- test/support/vcr_cassettes/web_engine_highlights_ruby_sample_1.yml
|
176
226
|
- test/support/vcr_cassettes/web_engine_is_accessible.yml
|
177
227
|
- test/test_helper.rb
|