snippeteer 0.1.0

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: 762100a898939f8f15917f878a8d74808b014e72
4
+ data.tar.gz: 4d5724e1217213c8785f24651056c5059c529233
5
+ SHA512:
6
+ metadata.gz: f2f1fe5b7d58d13b55c6efe6093d32f76ad9e683de6dfa0831bf682ba2822f3255b38633fb49b692e8c6f9345fa62ab32aa4805a5d611433b859a70db14c8c6c
7
+ data.tar.gz: e7544e3e86a77d7ded34f91506de0c2da8b504c5ea3e9cfef7afa3cb60f8f660536397e8fe7519c24c45e371630049d8eb8d2d492d080dc1aa8b14e094fd0526
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2013 feivel jellyfish
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,46 @@
1
+ # snippeteer
2
+ code snippet extractor & runner for Jekyll blog posts. test your examples with almost no effort!
3
+
4
+ ```shell
5
+ $ cat post.markdown
6
+ herp derp blog post
7
+
8
+ {% highlight c %}
9
+ int herp;
10
+ {% endhighlight %}
11
+
12
+ {% highlight python %}
13
+ puts('derpity')
14
+ {% endhighlight %}
15
+
16
+ {% highlight c %}
17
+ double derp = herp;
18
+ {% endhighlight %}
19
+
20
+ $ snippeteer snip post.markdown
21
+ wrote post.markdown.c
22
+ wrote post.markdown.py
23
+ $ cat post.markdown.c
24
+ int herp;
25
+ double derp = herp;
26
+ ```
27
+
28
+ `snippeteer` also knows how to run code in some languages directly:
29
+
30
+ ```shell
31
+ $ snippeteer run post.markdown
32
+ derpity
33
+ ```
34
+
35
+ ## extending
36
+
37
+ `snippeteer` can be extended to recognize new languages:
38
+
39
+ ```shell
40
+ $ cat snip_ext.rb
41
+ class Snippeteer::Lang
42
+ register "trendy", ".tr", "runtrendy"
43
+ end
44
+ $ snippeteer --load snip_ext.rb run trendy-lang-takes-hacker-news-by-storm.markdown
45
+ ```
46
+
data/bin/snippeteer ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'snippeteer'
4
+ require 'commander/import'
5
+
6
+ program :version, Snippeteer::VERSION
7
+ program :description, 'Code snippet extractor for Jekyll posts.'
8
+
9
+ default_scanners = [Snippeteer::LiquidHighlightScanner]
10
+
11
+ global_option '--load CONFIGS', Array, "Load CONFIGS before executing." do |configs|
12
+ configs.each {|cfg| load cfg}
13
+ end
14
+
15
+ command :snip do |c|
16
+ c.syntax = 'snippeteer snip [FILES ...]'
17
+ c.description = 'Extract snippets from files.'
18
+ c.action do |files, options|
19
+ files.each do |f|
20
+ Snippeteer::Writer.new(f, default_scanners).write_sources.values.each do |fn|
21
+ puts "wrote #{fn}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ command :run do |c|
28
+ c.syntax = 'snippeteer run [FILES ...]'
29
+ c.description = 'Run snippets from files'
30
+ c.option '--noclean', "Don't remove source files after running them."
31
+ c.action do |files, opts|
32
+ run, ok = [], true
33
+ files.each do |f|
34
+ puts opts.no_clean
35
+ run += Snippeteer::Writer.new(f, default_scanners).run_sources(!opts.noclean)
36
+ end
37
+ run.each do |filename, ran_ok|
38
+ if not ran_ok
39
+ $stderr.puts "# warning: execution of #{filename} finished with non-zero exit status"
40
+ ok = false
41
+ end
42
+ end
43
+ exit 1 if not ok
44
+ end
45
+ end
46
+
data/lib/snippeteer.rb ADDED
@@ -0,0 +1,147 @@
1
+ module Snippeteer
2
+ VERSION = '0.1.0'
3
+ # Container for code tagged with language metadata.
4
+ class Snippet < Struct.new(:lang, :code); end
5
+
6
+ # Filesystem interface for the document reader. Reads files
7
+ # and writes/runs extracted snippets.
8
+ class Writer
9
+ attr_reader :path, :scanners
10
+
11
+ # Takes a filename and a list of scanners. Scanners are expected to have
12
+ # a `scan' method that takes a string and returns a list of Snippets.
13
+ def initialize(path, scanners)
14
+ @path, @scanners = path, scanners
15
+ end
16
+
17
+ # Write extracted snippets to files according to their language. Returns
18
+ # a hash mapping language to filename.
19
+ def write_sources
20
+ basename = File.basename path
21
+ sources.each_with_object({}) do |snip, written|
22
+ lang, src = snip
23
+ srcname = basename + lang.ext
24
+ File.open(srcname, 'w') {|srcfile| srcfile.write src}
25
+ written[lang] = srcname
26
+ end
27
+ end
28
+
29
+ # Write extracted snippets, then execute them if an execution command is
30
+ # given for their language. By default, removes the written files after
31
+ # execution. Returns a list of filename, exit status pairs.
32
+ def run_sources(cleanup = true)
33
+ srcs = write_sources.each_with_object([]) do |written, run|
34
+ lang, srcfile = written
35
+ if lang.exec
36
+ run << [srcfile, system("#{lang.exec} #{srcfile}")]
37
+ FileUtils.rm srcfile if cleanup
38
+ end
39
+ end
40
+ end
41
+
42
+ def sources
43
+ Reader.new(File.read(@path), @scanners).sources
44
+ end
45
+ end
46
+
47
+ # Document reader. Extracts and aggregates snippets from data.
48
+ class Reader
49
+ attr_reader :data, :scanners
50
+ def initialize(data, scanners)
51
+ @data, @scanners = data, scanners
52
+ end
53
+
54
+ def snippets
55
+ scanners.reduce([]) {|snips, scanner| snips + scanner.scan(data)}
56
+ end
57
+
58
+ def sources
59
+ snippets.each_with_object({}) do |snip, srcs|
60
+ srcs[snip.lang] ||= ""
61
+ srcs[snip.lang] << snip.code
62
+ end
63
+ end
64
+ end
65
+
66
+ # Container & registry for language information.
67
+ class Lang < Struct.new(:ext, :exec)
68
+ UNKNOWN = new ".txt"
69
+ @registry = {}
70
+
71
+ class << self
72
+ # Define a new (or redefine an old) language, with
73
+ # filename extension and optional execution command.
74
+ def register(name, ext, exec = nil)
75
+ @registry[name] = new(ext, exec)
76
+ end
77
+
78
+ def find(lang)
79
+ if found = @registry.keys.find {|m| m == lang}
80
+ @registry[found]
81
+ else
82
+ UNKNOWN
83
+ end
84
+ end
85
+ end
86
+
87
+ # here's a super incomplete list of languages
88
+ register "haskell", ".hs", "runhaskell"
89
+ register "ruby", ".rb", "ruby"
90
+ register "python", ".py", "python"
91
+ register "c", ".c"
92
+ register "c++", ".c++"
93
+ register "php", ".php", "php -f"
94
+ register "perl", ".pl", "perl"
95
+ register "javascript", ".js"
96
+ register "coffeescript", ".coffee", "coffee"
97
+ register "clojure", ".clj", "clojure"
98
+ register "clojurescript", ".cljs"
99
+ register "erlang", ".erl"
100
+ register "lisp", ".lisp", "sbcl --script" # arbitrary + non-portable choice
101
+ register "shell", ".sh", "sh"
102
+ register "java", ".java"
103
+ register "lua", ".lua", "lua"
104
+ register "scheme", ".scm"
105
+ register "go", ".go"
106
+ register "ocaml", ".ml"
107
+ end
108
+
109
+ # A _very_ simple parser for Jekyll pages that tries to extract code from
110
+ # Liquid highlight tags and partition it by language. Should just work as
111
+ # long as you don't give it nested highlight blocks or something like that.
112
+ class LiquidHighlightScanner
113
+ HIGHLIGHT = /^\s*{%\s*highlight\s+(\w+).*%}\s*$/
114
+ ENDHIGHLIGHT = /^\s*{%\s*endhighlight\s*%}\s*$/
115
+
116
+ def self.scan(doc)
117
+ new(doc).scan
118
+ end
119
+
120
+ def initialize(doc)
121
+ @lines = doc.lines.each
122
+ @snips = []
123
+ end
124
+
125
+ def scan
126
+ unhighlit
127
+ rescue StopIteration
128
+ @snips
129
+ end
130
+
131
+ private
132
+ def highlit(lang)
133
+ snip = Snippet.new lang, ""
134
+ until (l = @lines.next) =~ ENDHIGHLIGHT
135
+ snip.code += l
136
+ end
137
+ @snips << snip
138
+ unhighlit
139
+ end
140
+
141
+ def unhighlit
142
+ until (l = @lines.next) =~ HIGHLIGHT; end
143
+ highlit Lang.find $1
144
+ end
145
+ end
146
+ end
147
+
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH << File.expand_path("../lib", __FILE__)
2
+ require 'snippeteer'
3
+ require 'rake'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'snippeteer'
7
+ spec.version = Snippeteer::VERSION
8
+ spec.author = 'feivel jellyfish'
9
+ spec.email = 'walpurgisriot@gmail.com'
10
+ spec.files = FileList['snippeteer.gemspec',
11
+ 'README.markdown',
12
+ 'LICENSE',
13
+ 'lib/*',
14
+ 'bin/*']
15
+ spec.test_files = FileList['test/**/*']
16
+ spec.executables = ["snippeteer"]
17
+ spec.bindir = 'bin'
18
+ spec.license = 'MIT/X11'
19
+ spec.homepage = 'http://github.com/walpurgisriot/jekyll-snippeteer'
20
+ spec.summary = 'Code snippet extractor & runner.'
21
+ spec.description = 'Code snippet extractor & runner for Jekyll posts.'
22
+ end
23
+
data/test/test.rb ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require_relative '../lib/snippeteer'
4
+
5
+ POST = <<EOF
6
+ hai this hurr is my blog
7
+ i have written sum coed:
8
+ {% highlight c %}
9
+ int num = 2;
10
+ {% endhighlight%}
11
+
12
+ {%highlight ruby%}
13
+ nums = [1,2,3] # lol
14
+ {% endhighlight %}
15
+
16
+ {% highlight c %}
17
+ const char *myTxt = "i am writin c";
18
+ // lol i dont get y C needs semmicolons?
19
+ {% endhighlight %}
20
+
21
+ <a href="mailto:the_code_kid93@yahoo.com">HIRE ME</a>
22
+ EOF
23
+
24
+ POST.freeze
25
+
26
+
27
+ class LangTest < Test::Unit::TestCase
28
+ def test_find
29
+ assert_equal Snippeteer::Lang.find("haskell"), Snippeteer::Lang.new(".hs", "runhaskell")
30
+ assert_equal Snippeteer::Lang.find("ruby"), Snippeteer::Lang.new(".rb", "ruby")
31
+ assert_equal Snippeteer::Lang.find("blargysploo"), Snippeteer::Lang::UNKNOWN
32
+ end
33
+
34
+ def test_register
35
+ # modifying entries
36
+ Snippeteer::Lang.register "ruby", ".rb", "jruby"
37
+ assert_equal Snippeteer::Lang.find("ruby").exec, "jruby"
38
+
39
+ # creating new entries
40
+ Snippeteer::Lang.register "made_up_lang", ".mul"
41
+ assert_equal Snippeteer::Lang.find("made_up_lang"), Snippeteer::Lang.new(".mul", nil)
42
+ end
43
+ end
44
+
45
+ class ScannerTest < Test::Unit::TestCase
46
+ def test_scan
47
+ results = Snippeteer::LiquidHighlightScanner.scan POST
48
+ assert_equal results.size, 3
49
+ assert_equal results.select {|r| r.lang.ext == ".c"}.size, 2
50
+ assert_equal results.select {|r| r.lang.ext == ".rb"}.size, 1
51
+
52
+ text = results.map(&:code).join
53
+ assert !(text =~ /HIRE ME/)
54
+ end
55
+ end
56
+
57
+ class ReaderTest < Test::Unit::TestCase
58
+ def lang(l)
59
+ Snippeteer::Lang.find l
60
+ end
61
+
62
+ def test_sources
63
+ srcs = Snippeteer::Reader.new(POST, [Snippeteer::LiquidHighlightScanner]).sources
64
+ assert_equal srcs.size, 2
65
+ assert srcs.has_key? lang "ruby"
66
+ assert srcs.has_key? lang "c"
67
+ assert_equal srcs[lang "c"].lines.size, 3
68
+ end
69
+ end
70
+
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snippeteer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - feivel jellyfish
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Code snippet extractor & runner for Jekyll posts.
14
+ email: walpurgisriot@gmail.com
15
+ executables:
16
+ - snippeteer
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - snippeteer.gemspec
21
+ - README.markdown
22
+ - LICENSE
23
+ - lib/snippeteer.rb
24
+ - bin/snippeteer
25
+ - test/test.rb
26
+ homepage: http://github.com/walpurgisriot/jekyll-snippeteer
27
+ licenses:
28
+ - MIT/X11
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.0.14
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Code snippet extractor & runner.
50
+ test_files:
51
+ - test/test.rb