prettyp 0.0.1

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: 6f5a14081112b48776bdb009a7b509ca08548d94
4
+ data.tar.gz: 6506aa55657f050cda05b958b377a15b92556024
5
+ SHA512:
6
+ metadata.gz: c28301c9b78b7a2d51809163b018a8a7922105883a2ff3e1588dd64e9cec6c3a3ae784da3a3894a31e1c222e6f9e1399cdc330eb18634337c2a713c7703d5a08
7
+ data.tar.gz: 4999d3c6478c700ff330af063863506a2f1d1c7c0960b2a87c42ca3656bacc5ef572713bb7a4a123c5090d12fd2037842a9fb5087f172b5d1e6403771d8d6a84
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ tags
16
+ /.vendor/
17
+ cscope.out
18
+ .starscope.db
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'pry', require: true
5
+ gem 'fakefs'
6
+ end
7
+
8
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jacob Evans
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Prettyp
2
+
3
+ One language formatter tool to rule them all.
4
+
5
+ ## Why?
6
+ I didn't like having to remember:
7
+
8
+ ```
9
+ pbpaste | xmllint --format -
10
+ cat log.json | python -m json.tool
11
+ ```
12
+
13
+ Why not just have a tool to do them all.
14
+
15
+ ## Installation
16
+
17
+ Install it yourself as:
18
+
19
+ $ gem install prettyp
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ pbpaste | prettyp format
25
+ cat test.json | prettyp format
26
+ prettyp format --file test.json
27
+ ```
28
+
29
+ ## Contributing
30
+
31
+ 1. Fork it ( https://github.com/dekz/prettyp/fork )
32
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
33
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
34
+ 4. Push to the branch (`git push origin my-new-feature`)
35
+ 5. Create a new Pull Request
36
+
37
+ ## TODO support ignoring the language classifier
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/prettyp ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require 'prettyp'
5
+ require 'thor'
6
+
7
+ class CLI < Thor
8
+ Prettyp::Logger.logger.level = ::Logger::WARN
9
+ desc "format", "formats input from either stdin or file (--file) and prints to stdout"
10
+ option :file
11
+ def format
12
+ service = Prettyp::FormatterService.new
13
+ text = if options[:file]
14
+ service.format_from_file(File.open(options[:file], 'r'))
15
+ else
16
+ service.format_from_stdin
17
+ end
18
+ puts text
19
+ end
20
+ end
21
+
22
+ CLI.start(ARGV)
data/lib/prettyp.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "prettyp/version"
2
+ require "prettyp/logger"
3
+ require 'prettyp/formatters'
4
+ require 'prettyp/formatter_service'
5
+
6
+ module Prettyp
7
+ end
@@ -0,0 +1,73 @@
1
+ require 'tempfile'
2
+
3
+ module Prettyp
4
+ module Formatter
5
+ class FormatError < StandardError; end
6
+ class Unimplemented < StandardError; end
7
+
8
+ class BaseFormatter
9
+ include Logger
10
+
11
+ def self.inherited clazz
12
+ @inherited_classes ||= []
13
+ @inherited_classes << clazz
14
+ end
15
+
16
+ def self.inherited_classes
17
+ @inherited_classes
18
+ end
19
+
20
+ def self.check_requirement
21
+ raise Unimplemented 'requirement'
22
+ end
23
+
24
+ def self.languages
25
+ []
26
+ end
27
+
28
+ def check_requirement
29
+ self.class.check_requirement
30
+ end
31
+
32
+ def format input, language
33
+ raise Unimplemented 'format'
34
+ end
35
+
36
+ protected
37
+ def execute_command command, on_error: nil, on_success: nil
38
+ logger.debug command
39
+
40
+ output = `#{command} 2>&1 `
41
+ success = !execute_error?
42
+
43
+ on_error.call(output) if !success && on_error
44
+ on_success.call(output) if success and on_success
45
+
46
+ output
47
+ end
48
+
49
+ def execute_error?
50
+ $? != 0
51
+ end
52
+
53
+ def with_file input, &block
54
+ return block.call(input) if input.is_a?(File) || input.is_a?(Tempfile)
55
+ with_tempfile(input, &block)
56
+ end
57
+
58
+ def with_tempfile input, &block
59
+ file = Tempfile.new('prettyp')
60
+ file.write(input)
61
+ begin
62
+ file.rewind
63
+ block.call(file)
64
+ ensure
65
+ file.close
66
+ file.unlink
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+
@@ -0,0 +1 @@
1
+ Dir.glob(File.dirname(__FILE__) + '/html/*') { |f| load f }
@@ -0,0 +1,32 @@
1
+ module Prettyp
2
+ module Formatter
3
+ module HTML
4
+ class Tidy < ::Prettyp::Formatter::BaseFormatter
5
+
6
+ def self.languages
7
+ ['HTML']
8
+ end
9
+
10
+ def self.executeable; 'tidy'; end
11
+
12
+ def self.check_requirement
13
+ !%x|which #{executeable}|.empty?
14
+ end
15
+
16
+ def format input, language
17
+ with_file(input) do |file|
18
+ with_tempfile '' do |tmp|
19
+ out = execute_command("#{self.class.executeable} -im #{file.path} -f #{tmp.path} -q",
20
+ #on_error: Proc.new { |output| raise FormatError, output })
21
+ on_error: Proc.new { })
22
+ out = File.read(file.path)
23
+ out
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1 @@
1
+ Dir.glob(File.dirname(__FILE__) + '/json/*') { |f| load f }
@@ -0,0 +1,24 @@
1
+ module Prettyp
2
+ module Formatter
3
+ module JSON
4
+ class Python < ::Prettyp::Formatter::BaseFormatter
5
+ def self.languages
6
+ ['JSON']
7
+ end
8
+
9
+ def self.executeable; 'python'; end
10
+ def self.check_requirement
11
+ !%x|which #{executeable}|.empty?
12
+ end
13
+
14
+ def format input, language
15
+ with_file(input) do |file|
16
+ out = execute_command("cat #{file.path} | #{self.class.executeable} -m json.tool",
17
+ on_error: Proc.new { |output| raise FormatError, output })
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
File without changes
@@ -0,0 +1 @@
1
+ Dir.glob(File.dirname(__FILE__) + '/xml/*') { |f| load f }
@@ -0,0 +1,27 @@
1
+ module Prettyp
2
+ module Formatter
3
+ module XML
4
+ class Xmllint < ::Prettyp::Formatter::BaseFormatter
5
+
6
+ def self.languages
7
+ [:xml, :html]
8
+ end
9
+
10
+ def self.executeable; 'xmllint'; end
11
+ def self.check_requirement
12
+ !%x|which #{executeable}|.empty?
13
+ end
14
+
15
+ def format input, language
16
+ extra_opts = '--html' if language.eql? :html
17
+ with_file(input) do |file|
18
+ out = execute_command("cat #{file.path} | #{self.class.executeable} --format #{extra_opts} -",
19
+ on_error: Proc.new { |output| raise FormatError, output })
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,30 @@
1
+ module Prettyp
2
+ class FormatterRegistry
3
+
4
+ attr_reader :formatters
5
+
6
+ def initialize formatters = Formatter::BaseFormatter.inherited_classes
7
+ determine_formatters formatters
8
+ end
9
+
10
+ def formatter_for language
11
+ formatters[format_language_key(language)].first
12
+ end
13
+
14
+ private
15
+ def determine_formatters formatters
16
+ our_formatters = Hash.new {|h,k| h[k]=[]}
17
+
18
+ formatters.each do |clazz|
19
+ clazz.languages.each { |l| our_formatters[format_language_key(l)] << clazz } if clazz.check_requirement
20
+ end
21
+
22
+ @formatters = our_formatters
23
+ end
24
+
25
+ def format_language_key l
26
+ l.downcase.to_sym
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,62 @@
1
+ require 'prettyp/language_detection_service'
2
+ require 'prettyp/formatter_registry'
3
+
4
+ module Prettyp
5
+ class FormatError < StandardError; end
6
+ class FormatterService
7
+ include Logger
8
+
9
+ def initialize(formatter_registry: FormatterRegistry.new, language_detection: LanguageDetectionService.new)
10
+ @formatter_registry = formatter_registry
11
+ @language_detection = language_detection
12
+ end
13
+
14
+ def format_from_file file
15
+ language = language_detection.detect_from_file(file)
16
+ format file, language
17
+ end
18
+
19
+ def format_from_stdin
20
+ input = $stdin.read
21
+
22
+ language = language_detection.detect_from_input(input)
23
+ with_tempfile input do |f|
24
+ format f, language
25
+ end
26
+ end
27
+
28
+ def format_as_language_from_file language, file
29
+ format file, language
30
+ end
31
+
32
+ def format_as_language_from_stdin language
33
+ input = $stdin.read
34
+
35
+ with_tempfile input do |f|
36
+ format f, language
37
+ end
38
+ end
39
+
40
+ private
41
+ attr_reader :formatter_registry, :language_detection
42
+
43
+ def format file, language
44
+ formatter = formatter_registry.formatter_for(language)
45
+ raise FormatError, "Cannot determine formatter for #{language} from #{formatter_registry.formatters}" unless formatter
46
+ formatter.new.format(file, language)
47
+ end
48
+
49
+ def with_tempfile input, &block
50
+ file = Tempfile.new('prettyp')
51
+ file.write(input)
52
+ begin
53
+ file.rewind
54
+ block.call(file)
55
+ ensure
56
+ file.close
57
+ file.unlink
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,4 @@
1
+ require 'prettyp/formatter/base_formatter'
2
+ require 'prettyp/formatter/xml'
3
+ require 'prettyp/formatter/json'
4
+ require 'prettyp/formatter/html'
@@ -0,0 +1,31 @@
1
+ require 'linguist'
2
+
3
+ module Prettyp
4
+ class LanguageDetectionService
5
+ # Our supported languages
6
+ POSSIBLE_LANGUAGE_NAMES = ['XML', 'Ruby', 'JSON', 'JavaScript', 'HTML']
7
+
8
+ def detect_from_file file
9
+ file_blob = Linguist::FileBlob.new(file.path)
10
+ language = file_blob.language
11
+ return format_language_key(language.name) if language
12
+
13
+ detect_from_input(file_blob.data)
14
+ end
15
+
16
+ def detect_from_input input
17
+ classified = Linguist::Classifier.classify(Linguist::Samples::DATA, input, possible).first
18
+ format_language_key(Linguist::Language[classified[0]].name)
19
+ end
20
+
21
+ private
22
+ def possible
23
+ @possible_languaes_list ||= POSSIBLE_LANGUAGE_NAMES.map { |n| Linguist::Language.find_by_name(n) }.map(&:name)
24
+ end
25
+
26
+ def format_language_key l
27
+ l.downcase.to_sym
28
+ end
29
+ end
30
+ end
31
+