hldr 0.1.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.
@@ -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: []