gist-compile 0.0.1

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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/gist-compile +179 -0
  3. data/lib/json-serializer.rb +115 -0
  4. metadata +125 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0404315290e1f5a70692d1451eff74a51fc71e9
4
+ data.tar.gz: b09dd574f835081e4976d7b022e52b79624c3dd2
5
+ SHA512:
6
+ metadata.gz: b2f3b8f401acb8ff8726ccaddb1e187c9c0fe6a3298536b764290a5eca1ef4ef3180691a88a82a59f9c1a9c6e40c359d14c5284ec361eaf4ccc3c2fceec88fb5
7
+ data.tar.gz: 07174faeccf7a99f4ec411536e8705de577e143c9a193d05b5289c91d99c34bc1a6b8d30ee1ec4f9022cd746d00933d50e56c42f760c89cfb5386255316f8a38
data/bin/gist-compile ADDED
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require "uri"
5
+ require "json"
6
+ require "thor"
7
+ require "paint"
8
+ require "rubygems"
9
+ require "nokogiri"
10
+ require "rest-client"
11
+ require_relative "../lib/json-serializer.rb"
12
+
13
+ GIST_BASE_URL = "https://gist.github.com"
14
+ GIST_USERCONTENT_BASE_URL = "https://gist.githubusercontent.com"
15
+ GIST_XPATH_IDENTIFIER = "//*[@id=\"js-flash-container\"]/div/div/div/div/div/span/a[3]"
16
+
17
+ GIST_METADATA_HOOKS = Hash.new
18
+ GIST_METADATA_HOOKS["Title"] = "Title:"
19
+ GIST_METADATA_HOOKS["Authors"] = "Authors:"
20
+ GIST_METADATA_HOOKS["Description"] = "Description:"
21
+ GIST_METADATA_HOOKS["Section"] = "Section:"
22
+ GIST_METADATA_HOOKS["Subsection"] = "Subsection:"
23
+
24
+ class GistCompile < Thor
25
+ no_commands do
26
+ def load_gists(usernames)
27
+ thread_arr = []
28
+ metadata = []
29
+ elements = []
30
+ gists_data = Hash.new
31
+ username_urls = []
32
+
33
+ usernames.each do |u|
34
+ username_urls.push(URI::join(GIST_BASE_URL+'/', u.strip()).to_s)
35
+ end
36
+
37
+ username_urls.each do |username_url|
38
+ page = 1
39
+ while page < 1000
40
+ gist_url_current_page = URI::join(username_url+'/', "?page=#{page}").to_s
41
+ raw_html = Nokogiri::HTML(RestClient.get(gist_url_current_page))
42
+ new_elements = raw_html.css(GIST_XPATH_IDENTIFIER)
43
+ if new_elements.length == 0
44
+ break
45
+ else
46
+ elements.concat(new_elements)
47
+ end
48
+ page = page + 1
49
+ end
50
+ end
51
+
52
+ puts "Processing #{elements.length} gists..."
53
+
54
+ elements.each do |element|
55
+ thread_arr.push(
56
+ Thread.new {
57
+ individual_gist_url = URI::join(GIST_BASE_URL, element['href']+'/').to_s
58
+ individual_gist_url_raw = URI::join(GIST_USERCONTENT_BASE_URL, element['href']+'/', 'raw').to_s
59
+ individual_gist_html = Nokogiri::HTML(RestClient.get(individual_gist_url_raw))
60
+ metadata_for_gist = process_raw_gist(individual_gist_html.xpath("//*/body/p")[0].text)
61
+ if metadata_for_gist != nil && !metadata_for_gist.empty?
62
+ $stdout.write(" • #{individual_gist_url}: " + Paint["[", :yellow] + Paint["OK", :green] + Paint["]",:yellow]+"\r\n")
63
+ $stdout.flush
64
+ GIST_METADATA_HOOKS.each do |key, value|
65
+ if !metadata_for_gist.key? key
66
+ metadata_for_gist[key] = nil
67
+ end
68
+ end
69
+ metadata_for_gist["URL"] = individual_gist_url
70
+ metadata_for_gist["URL_RAW"] = individual_gist_url_raw
71
+ metadata_for_gist["URL_USER"] = /github.com\/[A-Za-z0-9]*/.match(individual_gist_url)
72
+ metadata.push(metadata_for_gist)
73
+ else
74
+ puts " • #{individual_gist_url}: " + Paint["[", :yellow] + Paint["ERR", :red] + Paint["]",:yellow]
75
+ end
76
+ }
77
+ )
78
+ end
79
+
80
+ thread_arr.each{ |t| t.join() }
81
+
82
+ File.open("./prod/gists.json","w") do |f|
83
+ pretty_string = JSON.pretty_generate(metadata.sort_by {|item| item["Title"]})
84
+ f.write(pretty_string)
85
+ f.close()
86
+ end
87
+ end
88
+
89
+ def process_raw_gist (raw_text)
90
+ metadata = Hash.new
91
+
92
+ comment_char = nil
93
+ lines = raw_text.lines()
94
+ last_known_key = nil
95
+
96
+ hooks_remaining = GIST_METADATA_HOOKS.clone
97
+
98
+ for index in 0..lines.length-1
99
+ stripped_line = lines[index].strip()
100
+ if stripped_line != nil && !stripped_line.empty?
101
+ if stripped_line.start_with?("#!")
102
+ next
103
+ end
104
+
105
+ if comment_char == nil
106
+ index = stripped_line.index(GIST_METADATA_HOOKS["Title"])
107
+ if index == nil
108
+ return nil
109
+ else
110
+ comment_char = stripped_line[0..index-1].strip()
111
+ end
112
+ end
113
+ if stripped_line.start_with?(comment_char)
114
+ stripped_line = stripped_line.sub(comment_char,'').strip()
115
+ if stripped_line.empty?
116
+ last_known_key = nil
117
+ break
118
+ end
119
+ hook_data = search_line_for_hooks(hooks_remaining, last_known_key, stripped_line)
120
+ if hook_data == nil
121
+ break
122
+ else
123
+ parsed_key = hook_data[0]
124
+ parsed_value = hook_data[1]
125
+
126
+ last_known_key = parsed_key
127
+ if metadata.key? parsed_key # is the key already in the hash?
128
+ metadata[parsed_key] = metadata[parsed_key] + " #{parsed_value}" # append
129
+ else
130
+ metadata[parsed_key] = parsed_value
131
+ end
132
+ end
133
+ else
134
+ last_known_key = nil
135
+ break
136
+ end
137
+ end
138
+ end
139
+
140
+ return metadata
141
+ end
142
+
143
+ def search_line_for_hooks(hooks_remaining, last_known_key, line)
144
+ hooks_remaining.each do |key, value|
145
+ if line.include? value
146
+ hooks_remaining.delete(key)
147
+ return [key, line.sub(value, '')]
148
+ end
149
+ end
150
+
151
+ if last_known_key != nil
152
+ return [last_known_key, line];
153
+ end
154
+
155
+ return nil
156
+ end
157
+ end
158
+
159
+ desc "start", "Run the gist-compile"
160
+ method_option :username, :aliases => "-u", :desc => "username(s) to run with, seperated by comma: \"claymcleod, othername\""
161
+ method_option :linkauthor, :aliases => "--link-author", :desc => "When serializing in HTML, the authors page will be linked", :default => false
162
+ def start
163
+ usernames = options[:username]
164
+ linkauthor = options[:linkauthor]
165
+
166
+ if usernames == nil
167
+ puts "You must specify a username! (eg. -u \"claymcleod\")"
168
+ return
169
+ end
170
+
171
+ load_gists(usernames.split(","))
172
+ serializer = JSONSerializer.new(File.open("./prod/gists.json","r").read, linkauthor)
173
+ serializer.to_md
174
+ serializer.to_html
175
+ end
176
+ end
177
+
178
+ GistCompile.start(ARGV)
179
+
@@ -0,0 +1,115 @@
1
+ require 'json'
2
+
3
+ class JSONSerializer
4
+ attr_accessor :json
5
+ attr_accessor :linkauthor
6
+
7
+ def initialize(json, linkauthor)
8
+ @json = json
9
+ @linkauthor = linkauthor
10
+ end
11
+
12
+ def compile
13
+ structured_gists = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
14
+
15
+ entries = JSON.parse(json)
16
+ entries.each do |arr|
17
+ title = arr["Title"] != nil ? arr["Title"].strip() : nil
18
+ authors = arr["Authors"] != nil ? arr["Authors"].strip() : nil
19
+ description = arr["Description"] != nil ? arr["Description"].strip() : nil
20
+ section = arr["Section"] != nil ? arr["Section"].strip() : nil
21
+ subsection = arr["Subsection"] != nil ? arr["Subsection"].strip() : nil
22
+ url = arr["URL"] != nil ? arr["URL"].strip() : nil
23
+ url_user = arr["URL_USER"] != nil ? arr["URL_USER"].strip() : nil
24
+
25
+ if title == nil
26
+ puts "Error: A title must be included for #{url}"
27
+ next
28
+ end
29
+
30
+ if section == nil || subsection == nil
31
+ puts "Error: #{title} must have a section and subsection to be compiled!"
32
+ next
33
+ end
34
+
35
+ structured_gists[section][subsection][title] = {"Authors"=>authors, "Description"=>description,
36
+ "URL"=>url, "URL_USER"=>url_user}
37
+ end
38
+ structured_gists = structured_gists.sort.to_h
39
+ structured_gists.keys.each do |k|
40
+ structured_gists[k] = structured_gists[k].sort.to_h
41
+ structured_gists[k].keys.each do |l|
42
+ structured_gists[k][l] = structured_gists[k][l].sort.to_h
43
+ end
44
+ end
45
+
46
+ return structured_gists
47
+ end
48
+
49
+ def to_md
50
+ structured_gists = compile()
51
+ File.open("./prod/gists.md","w") do |f|
52
+ structured_gists.each do |j, v|
53
+ f.puts("# #{j}\r")
54
+ structured_gists[j].each do |k, v|
55
+ f.puts("### #{k}\r")
56
+ f.puts("\r\n")
57
+ structured_gists[j][k].each do |t, v|
58
+ f.puts("##### #{t}\r")
59
+ structured_gists[j][k][t].each do |l, v|
60
+ if v != nil
61
+ f.puts("* #{l}: #{v}\r")
62
+ end
63
+ end
64
+ f.puts("\r\n")
65
+ end
66
+ end
67
+ end
68
+ f.close()
69
+ end
70
+ end
71
+
72
+ def to_html
73
+ structured_gists = compile()
74
+ File.open("./prod/gists.html","w") do |f|
75
+ f.puts("<!DOCTYPE HTML>")
76
+ f.puts("<html>")
77
+ f.puts(" <head>\n <meta charset=\"UTF-8\">\n </head>");
78
+ f.puts(" <body>")
79
+ f.puts(" Generated by <a href=\"https://github.com/claymcleod/gist-compile\">gist-compile</a> at "+Time.new.strftime("%Y-%m-%d %H:%M:%S"))
80
+ structured_gists.each do |j, v|
81
+ f.puts(" <div class=\"section\">\r")
82
+ f.puts(" <a id=\"#{j}\"></a>")
83
+ f.puts(" <h1>#{j}</h1>\r")
84
+ f.puts(" </div>")
85
+ structured_gists[j].each do |k, v|
86
+ f.puts(" <h2>#{k}</h2>\r")
87
+ f.puts("\r\n")
88
+ structured_gists[j][k].each do |t, v|
89
+ url= structured_gists[j][k][t]["URL"]
90
+ if url == nil
91
+ f.puts(" <h3>#{t}</h3>\r")
92
+ else
93
+ f.puts(" <h3><a href=\'#{url}\'>#{t}</a></h3>")
94
+ end
95
+ f.puts(" <ul>");
96
+ structured_gists[j][k][t].each do |l, v|
97
+ if l != "URL" && l != "URL_USER" && v != nil
98
+ if linkauthor && l == "Authors"
99
+ f.puts(" <li>#{l}: <a href=\"http://#{structured_gists[j][k][t]["URL_USER"]}\">#{v}</a></li>\r")
100
+ else
101
+ f.puts(" <li>#{l}: #{v}</li>\r")
102
+ end
103
+ end
104
+ end
105
+ f.puts("\r\n")
106
+ f.puts(" </ul>\r")
107
+ end
108
+ end
109
+ end
110
+ f.puts(" </body>");
111
+ f.puts("</html>");
112
+ f.close()
113
+ end
114
+ end
115
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gist-compile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Clay McLeod
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.19.1
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.19.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 0.19.1
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.19.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: paint
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.0
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0.9'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 0.9.0
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0.9'
53
+ - !ruby/object:Gem::Dependency
54
+ name: nokogiri
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.6.6
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.6.6
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.6.6
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.6.6
73
+ - !ruby/object:Gem::Dependency
74
+ name: rest-client
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 1.7.2
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.7.2
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.7.2
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.7.2
93
+ description: ''
94
+ email: clay.l.mcleod@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - bin/gist-compile
100
+ - lib/json-serializer.rb
101
+ homepage: http://github.com/claymcleod/gist-compile
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.4.5
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Gist-compile will compile Github gists into an intelligible, book like, form.
125
+ test_files: []