hldr 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,78 @@
1
+ # Hldr
2
+ A Ruby gem to generate portable interactive documents by compiling all linked assets from an HTML document into a single file (rendered to `stdout`). The value of the Word document is diminishing by the minute!
3
+
4
+ Suppose you have a somewhat complicated, well broken out HTML document or front-end prototype that you want to quickly show a non-technical colleague, Bernard. Your document may look like this:
5
+
6
+ .
7
+ └── img
8
+ │ ├── icons
9
+ │ │ └── star.png
10
+ │ └── cake_decors.png
11
+ │ └── kittens.png
12
+ ├── js
13
+ │ ├── app.js
14
+ │ └── jquery.js
15
+ ├── css
16
+ │ ├── app.css
17
+ │ └── bootstrap.css
18
+
19
+ └── cakeRecipe.html
20
+
21
+ Wouldn't it be great if we could quickly compile all of this into a **single** file to give Bernard?
22
+
23
+ $ hldr cakeRecipe.html > flatfile.html
24
+
25
+ ![There can be only be one](http://cdn1-www.craveonline.com/assets/uploads/2011/01/file_130400_2_highlander04.jpg)
26
+
27
+ Yeah, obviously the output is a lot bigger than the original structure or a zip archive (especially if embedding images), but this is easier and cleaner for all parties involved. The vision for Hldr is twofold:
28
+
29
+ 1. Allowing (even non-technical) content creators to more easily leverage powerful interactive frameworks within their document.
30
+ 1. Make HTML front-end prototype sharing quick and easy.
31
+
32
+ ## Usage
33
+
34
+ Installation is simple, just suck down the gem via `gem install hldr`
35
+
36
+ ## Really advanced usage
37
+
38
+ $ hldr new cakeRecipe
39
+ $ cd cakeRecipe
40
+
41
+ $ hldr add bootstrap-3.0.0-rc2
42
+ $ hldr add jquery-mobile js
43
+ $ hldr add d3 js
44
+ $ hldr add flatui css
45
+ $ hldr add anotherCssJsFw
46
+
47
+ As a bonus, swapping out assets is a breeze:
48
+
49
+ $ hldr rm bootstrap-3.0.0-rc2
50
+ $ hldr add bootstrap-2.3.0
51
+ $ hldr cakeRecipe.md > flatCakeRecipeFile.html
52
+
53
+ ## Example Config File
54
+
55
+ scaffolding:
56
+ - http://somecdn.com/css/bootstrap.min.css
57
+ - http://somecdn.com/js/BBD-G23-4SIOU23-452 : js
58
+
59
+ ## The Future
60
+ - [x] ship anything
61
+ - [ ] compress images, html, js and css
62
+ - [ ] templates
63
+ - [ ] support md
64
+ - [ ] support haml
65
+ - [ ] Keep everything in .hldr cache
66
+ - [ ] fetch remotes
67
+ - [ ] support inline of css `@import`
68
+ - [ ] support inline of css `@import` media queries
69
+ - [ ] support inline of css fonts
70
+ - [ ] option to compress images below 32k for IE8 support
71
+ - [ ] support css image inline
72
+ - [ ] create gem that installs to path
73
+ - [ ] handle css, scss, less, sass
74
+ - [ ] handle requireJs
75
+ - [ ] set max cache size in config
76
+
77
+ ## Bugs
78
+ * Handle malformed input (ie file not found, etc)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require 'hldr/hldr_entry'
@@ -0,0 +1,2 @@
1
+ require 'hldr/hldr_entry'
2
+
@@ -0,0 +1,53 @@
1
+ require 'trollop'
2
+ require 'hldr/hldr_processor'
3
+ require 'hldr/hldr_globals'
4
+
5
+ hldr_opts = Trollop::options do
6
+ version "Hldr #{HLDR_VERSION} (c) 2013 Nate Fisher. \n\nThere can be only one!"
7
+ banner <<-EOS
8
+ Hldr - Generate a flat HTML file from linked assets.
9
+
10
+ Usage:
11
+ hldr [options] <file>
12
+ hldr <command> [args]
13
+
14
+ Examples:
15
+ hldr index.html > flat.html
16
+ hldr index.md > flat.html
17
+
18
+ Commands:
19
+ update Updates external content in the config file and stores to cache
20
+ init Creates a config file
21
+ new NAME Creates a new document folder, empty contents and a config file
22
+
23
+ Options:
24
+
25
+ EOS
26
+
27
+ opt :no_embed, "Inhibits base64 data URI image embedding", :default => true
28
+
29
+ end
30
+
31
+ hldr_cmd = ARGV.shift
32
+ case hldr_cmd
33
+ when "update"
34
+ # update cache from config file
35
+ when "init"
36
+ # create config file
37
+ HldrProcessor::generate_config
38
+ HldrProcessor::generate_cache
39
+ when "new"
40
+ if ARGV.first.nil?
41
+ puts "Name of document required for NEW command."
42
+ else
43
+ # create project folder
44
+ end
45
+ else
46
+ # no subcommand entered
47
+ if hldr_cmd.nil?
48
+ Trollop::die "No input given."
49
+ else
50
+ # Processing file
51
+ puts HldrProcessor.new(hldr_cmd, hldr_opts).to_s
52
+ end
53
+ end
@@ -0,0 +1 @@
1
+ HLDR_VERSION = "0.1.1"
@@ -0,0 +1,86 @@
1
+ require 'nokogiri'
2
+ require 'yaml'
3
+ require 'hldr/inliners/script_inliner'
4
+ require 'hldr/inliners/image_inliner'
5
+ require 'hldr/inliners/style_inliner'
6
+
7
+ class HldrProcessor
8
+
9
+ def initialize(location, options)
10
+ begin
11
+ @doc = Nokogiri::HTML(open(location))
12
+ rescue
13
+ puts "Could not open input file '#{location}'"
14
+ exit(1)
15
+ end
16
+ @options = options
17
+ end
18
+
19
+ def to_s
20
+
21
+ ## add config file scaffolding
22
+ add_scaffolding
23
+
24
+ ## process inlining
25
+ inline_assets
26
+
27
+ return @doc.to_html
28
+
29
+ end
30
+
31
+ def add_scaffolding
32
+
33
+ hldr_config = YAML.load_file('.hldrconfig')
34
+ hldr_config["scaffolding"].each do |resource|
35
+
36
+ # if ends in .css or is a hash with value of css, add style
37
+ if resource[-4..-1] == ".css"
38
+
39
+ css_res = Nokogiri::XML::Node.new "style", @doc
40
+ css_res.content = open(resource).read
41
+ css_res[:type] = "text/css"
42
+
43
+ head = @doc.at_css("html")
44
+ head << css_res
45
+
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ def inline_assets
53
+
54
+ inliners = {
55
+ :link => StyleInliner,
56
+ :script => ScriptInliner
57
+ }
58
+
59
+ # inhibit embedding images if flag set
60
+ if @options[:no_embed]
61
+ inliners[:img] = ImageInliner
62
+ end
63
+
64
+ inliners.each do |tag, inliner|
65
+
66
+ @doc.css(tag.to_s).each do |element|
67
+ inliner::embed(element)
68
+ end
69
+
70
+ end
71
+
72
+
73
+
74
+ end
75
+
76
+ # creates a cache location
77
+ def HldrProcessor.generate_cache
78
+ Dir::mkdir ".hldr" if !Dir::exist? ".hldr"
79
+ end
80
+
81
+ # creates a new config file
82
+ def HldrProcessor.generate_config
83
+ File::open ".hldrconfig", "w" if !File::exist? ".hldrconfig"
84
+ end
85
+
86
+ end
@@ -0,0 +1,19 @@
1
+ require 'base64'
2
+ require 'hldr/inliners/inliner'
3
+
4
+ class ImageInliner < Inliner
5
+ def ImageInliner.embed(element)
6
+
7
+ # try to retrieve content
8
+ content = getContent(element[:src])
9
+ return if content[:data].nil?
10
+
11
+ # create embedded data uri
12
+ data = "data:#{content[:type]};base64,"
13
+ data += Base64::encode64(content[:data])
14
+
15
+ # embed content
16
+ element[:src] = data
17
+
18
+ end
19
+ end
@@ -0,0 +1,48 @@
1
+ require 'open-uri'
2
+
3
+ class Inliner
4
+
5
+ def Inliner.get_image_extension(local_file_path)
6
+ # take from Alain Beauvois's post in
7
+ # http://stackoverflow.com/questions/4600679/detect-mime-type-of-uploaded-file-in-ruby
8
+
9
+ png = Regexp.new("\x89PNG".force_encoding("binary"))
10
+ jpg = Regexp.new("\xff\xd8\xff\xe0\x00\x10JFIF".force_encoding("binary"))
11
+ jpg2 = Regexp.new("\xff\xd8\xff\xe1(.*){2}Exif".force_encoding("binary"))
12
+
13
+ case IO.read(local_file_path, 10)
14
+ when /^GIF8/
15
+ 'image/gif'
16
+ when /^#{png}/
17
+ 'image/png'
18
+ when /^#{jpg}/
19
+ 'image/jpg'
20
+ when /^#{jpg2}/
21
+ 'image/jpg'
22
+ else
23
+ mime_type = `file #{local_file_path} --mime-type`.gsub("\n", '') # Works on linux and mac
24
+ raise UnprocessableEntity, "unknown file type" if !mime_type
25
+ mime_type.split(':')[1].split('/')[1].gsub('x-', '').gsub(/jpeg/, 'jpg').gsub(/text/, 'txt').gsub(/x-/, '')
26
+ end
27
+
28
+ end
29
+
30
+ def Inliner.getContent(location)
31
+
32
+ content = Hash.new
33
+
34
+ begin
35
+ if location[0..3] == "http"
36
+ content[:data] = open(location).read
37
+ content[:type] = open(location).meta["content-type"]
38
+ else
39
+ content[:data] = File::open(location, "rb").read
40
+ content[:type] = self.get_image_extension(location)
41
+ end
42
+ rescue
43
+ end
44
+
45
+ return content
46
+
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ require 'hldr/inliners/inliner'
2
+
3
+ class ScriptInliner < Inliner
4
+ def ScriptInliner.embed(element)
5
+
6
+ # ignore if content exists within tags
7
+ return if element.content &&
8
+ !element.content.strip.empty?
9
+
10
+ # try to retrieve content
11
+ content = getContent(element[:src])
12
+ return if content[:data].nil?
13
+
14
+ # remove src attribute
15
+ element.attributes["src"].remove
16
+
17
+ # force script type to javascript if null
18
+ element[:type] = "text/javascript" if
19
+ element[:type].nil? || element[:type] == ""
20
+
21
+ # embed content
22
+ element.content = content[:data]
23
+
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ require 'hldr/inliners/inliner'
2
+
3
+ class StyleInliner < Inliner
4
+ def StyleInliner.embed(element)
5
+
6
+ # try to retrieve content
7
+ content = getContent(element[:href])
8
+ return if content[:data].nil?
9
+
10
+ # keep media and type; remove all other params
11
+ whitelist = ["type", "media"]
12
+ element.attributes.each do |key, val|
13
+ if !whitelist.include?(key)
14
+ element.attributes[key].remove
15
+ end
16
+ end
17
+
18
+ # force rel type to style if null
19
+ element[:type] = "text/css" if
20
+ element[:type].nil? || element[:type] == ""
21
+
22
+ # rename tag to style
23
+ element.name = "style"
24
+
25
+ # embed content
26
+ element.content = content[:data]
27
+
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'hldr'
3
+
4
+ class HldrProcessorTest < Test::Unit::TestCase
5
+ def test_something
6
+ assert_equal 1,1
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hldr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nate Fisher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.6'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
30
+ description: ! 'Hldr is a utility to compile all linked assets from an html document
31
+ into a single file, rendered to STDOUT. The point is to allow content creators to
32
+ more easily use powerful interactive frameworks within their document. '
33
+ email: nate.scott.fisher@gmail.com
34
+ executables:
35
+ - hldr
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - bin/hldr
40
+ - lib/hldr.rb
41
+ - lib/hldr/inliners/image_inliner.rb
42
+ - lib/hldr/inliners/inliner.rb
43
+ - lib/hldr/inliners/style_inliner.rb
44
+ - lib/hldr/inliners/script_inliner.rb
45
+ - lib/hldr/hldr_processor.rb
46
+ - lib/hldr/hldr_entry.rb
47
+ - lib/hldr/hldr_globals.rb
48
+ - test/test_inliner.rb
49
+ - Readme.md
50
+ - Rakefile
51
+ homepage: http://github.com/thenatefisher/hldr
52
+ licenses:
53
+ - MIT
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.24
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Generate a flat HTML file from linked assets
76
+ test_files: []