pmlcode 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 454dcaffe9ac7b63687a11ae68c4542be8b72676
4
- data.tar.gz: febd592ae42c593fcdfe1d2152f09092e8b44839
3
+ metadata.gz: f7c9d54c8aff1abb04b6b9c83b086c937cc95faa
4
+ data.tar.gz: 05225b9edfdfa6ea2eeff33bca12b24bea7e5098
5
5
  SHA512:
6
- metadata.gz: 220ab845e2e4432e435d1bd4acb5a8456ec55f55f2f0d08e8adc2db1f2752d07858de5b99fa9355fd987c4da0ccef7dab89240d7116338e75bc68ba31eb8000d
7
- data.tar.gz: 834b6644bc03c7ee1bfd07711641a0e4d21f8833f83af4466f9a2b0d3c07c17584ed54a1f810c2ac0932af49e6341ad227089abe62127647e98c38e4f1c02358
6
+ metadata.gz: f7bc407d5a5a7b7edb8fc1fad07d616fc7609dbcc3dfdb4c216d1eed5d05e59b13f6250415223bf5471425782635228d0ac852faba56a04fc80b32f75b4eb7a0
7
+ data.tar.gz: 192249c2ab7b04ebfa7441f20facdc4300771834104437c723d12344098faff726667b9acf2e28597dbbfc141f3b6e17e468a977b776f233d71fb284c121e45c
data/README.md CHANGED
@@ -23,15 +23,19 @@ Will generate the referenced file, extracting it from the
23
23
  `origin/02-testing.01-start` ref of `/path/to/git/working/copy`.
24
24
 
25
25
  You can also extract the entire branch using the `-t full` option,
26
- process as many `.pml` files as you like at once, customize the
27
- pattern used to extract the metadata from filename, and more.
26
+ process as many `.pml` files as you like at once, be warned of missing
27
+ parts, see the file content (incl highlights), customize the
28
+ pattern used to extract the metadata from the filename, and more.
28
29
 
29
- See `pmlcode --help` for more details.
30
+ See `pmlcode --help` for more details (or read `USAGE`
31
+ and the options in [PMLCode::CLI](./lib/pmlcode/cli.rb)).
30
32
 
31
33
  ## Contributing
32
34
 
33
- Bug reports and pull requests are welcome on GitHub at https://github.com/bruce/pmlcode.
35
+ Bug reports and pull requests are welcome on GitHub at
36
+ https://github.com/bruce/pmlcode.
34
37
 
35
38
  ## License
36
39
 
37
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
40
+ The gem is available as open source under the terms of
41
+ the [MIT License](http://opensource.org/licenses/MIT).
data/lib/pmlcode.rb CHANGED
@@ -1,8 +1,14 @@
1
- require "pmlcode/version"
2
-
3
1
  require "nokogiri"
2
+ require "rainbow"
3
+
4
+ require "fileutils"
5
+
6
+ require "pmlcode/version"
4
7
 
5
8
  module PMLCode
6
9
  autoload :CLI, 'pmlcode/cli'
7
10
  autoload :Updater, 'pmlcode/updater'
11
+ autoload :Content, 'pmlcode/content'
12
+ autoload :Display, 'pmlcode/display'
13
+ autoload :Source, 'pmlcode/source'
8
14
  end
data/lib/pmlcode/cli.rb CHANGED
@@ -8,6 +8,8 @@ module PMLCode::CLI
8
8
 
9
9
  pmlcode [PML_PATH, ...] [OPTIONS]
10
10
 
11
+ PML_PATHs can optionally include a :LINENUM suffix.
12
+
11
13
  ## SYNOPSIS
12
14
 
13
15
  Looks for `<embed>` tags whose `file` attribute match `--pattern`, extracting the
@@ -80,11 +82,11 @@ module PMLCode::CLI
80
82
  parser = build_parser(options)
81
83
  parser.parse!(args)
82
84
 
83
- files = prepare(options, parser, args)
85
+ sources = prepare(options, parser, args)
84
86
 
85
- files.each do |pml|
86
- options.pml = pml
87
- options.output = File.dirname(pml)
87
+ sources.each do |source|
88
+ options.source = source
89
+ options.output = File.dirname(source.path)
88
90
  update!(options)
89
91
  end
90
92
 
@@ -119,14 +121,14 @@ module PMLCode::CLI
119
121
  $stderr.puts parser
120
122
  exit
121
123
  end
122
- files = args.map { |pml| File.expand_path(pml) }
123
- missing = files.select { |pml| !File.exists?(pml) }
124
+ sources = args.map { |pml| PMLCode::Source.parse(pml) }
125
+ missing = sources.select(&:missing?)
124
126
  unless missing.empty?
125
- $stderr.puts "PML files #{missing} not found"
127
+ $stderr.puts "PML sources #{missing} not found"
126
128
  puts parser
127
129
  exit
128
130
  end
129
- files
131
+ sources
130
132
  end
131
133
 
132
134
  def self.build_parser(options)
@@ -145,6 +147,18 @@ module PMLCode::CLI
145
147
  options.pattern = Regexp.new(value)
146
148
  end
147
149
 
150
+ opts.on('-c', '--content', "Show content") do
151
+ options.content = true
152
+ end
153
+
154
+ opts.on("-V", "--verbose", "Verbose output (Only useful with --content)") do
155
+ options.verbose = true
156
+ end
157
+
158
+ opts.on('-x', '--dry-run', "Dry run (do not write files)") do
159
+ options.dry_run = true
160
+ end
161
+
148
162
  opts.on_tail("-h", "--help", "Show this message") do
149
163
  puts opts
150
164
  exit
@@ -0,0 +1,98 @@
1
+ class PMLCode::Content
2
+ include Enumerable
3
+
4
+ def self.parse(text)
5
+ parser = Parser.new(text)
6
+ new(parser.result)
7
+ end
8
+
9
+ def initialize(lines)
10
+ @lines = lines
11
+ end
12
+
13
+ def has_part?(name)
14
+ @lines.any? { |l| l.in_part?(name) }
15
+ end
16
+
17
+ def each(&block)
18
+ @lines.each(&block)
19
+ end
20
+
21
+ def to_s
22
+ @lines.map(&:text)
23
+ end
24
+
25
+ class Line
26
+
27
+ attr_reader :text
28
+
29
+ def initialize(text, parts = [], highlighted = false)
30
+ @text = text
31
+ @parts = parts
32
+ @highlighted = highlighted
33
+ end
34
+
35
+ def in_part?(part = nil)
36
+ if part
37
+ @parts.include?(part)
38
+ else
39
+ !@parts.empty?
40
+ end
41
+ end
42
+
43
+ def highlighted?
44
+ @highlighted
45
+ end
46
+
47
+ end
48
+
49
+ class Parser
50
+
51
+ PART_START = /START:\s?(\S+)/
52
+ PART_END = /END:\s?(\S+)/
53
+
54
+ HL_START = /START_HIGHLIGHT/
55
+ HL_END = /END_HIGHLIGHT/
56
+
57
+ def initialize(raw)
58
+ @raw = raw
59
+ end
60
+
61
+ def result
62
+ @result ||= run
63
+ end
64
+
65
+ private
66
+
67
+ def run
68
+ @parts = []
69
+ @highlighted = nil
70
+ lines.map(&method(:process)).compact
71
+ end
72
+
73
+ def process(text)
74
+ case text
75
+ when PART_START
76
+ @parts << $1
77
+ nil
78
+ when PART_END
79
+ @parts.reject! { |part| part == $1 }
80
+ nil
81
+ when HL_START
82
+ @highlighted = true
83
+ nil
84
+ when HL_END
85
+ @highlighted = false
86
+ nil
87
+ else
88
+ Line.new(text, @parts.dup, @highlighted)
89
+ end
90
+ end
91
+
92
+ def lines
93
+ @raw.split(/\r?\n/)
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,31 @@
1
+ class PMLCode::Display
2
+
3
+ INDENT = " " * 4
4
+
5
+ def initialize(content, part, options)
6
+ @content = content
7
+ @part = part
8
+ @options = options
9
+ end
10
+
11
+ def to_s
12
+ INDENT + "```\n" + \
13
+ @content.map(&method(:format_line)).compact.map { |l| INDENT + l }.join("\n") + "\n" + \
14
+ INDENT + "```"
15
+ end
16
+
17
+ private
18
+
19
+ def format_line(line)
20
+ if @part && !line.in_part?(@part) && @options.verbose
21
+ Rainbow(line.text).black
22
+ elsif !@part || (@part && line.in_part?(@part))
23
+ if line.highlighted?
24
+ Rainbow(line.text).yellow.bold
25
+ else
26
+ line.text
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,25 @@
1
+ class PMLCode::Source
2
+
3
+ PATTERN = /^(?<path>.+?)(:(?<line>\d+):?)?$/
4
+
5
+ def self.parse(text)
6
+ if (match = text.match(PATTERN))
7
+ new(match[:path], match[:line] ? Integer(match[:line]) : nil)
8
+ end
9
+ end
10
+
11
+ attr_reader :path, :line
12
+ def initialize(path, line)
13
+ @path = File.expand_path(path)
14
+ @line = line
15
+ end
16
+
17
+ def missing?
18
+ !File.exists?(@path)
19
+ end
20
+
21
+ def to_s
22
+ [@path, @line].join(":")
23
+ end
24
+
25
+ end
@@ -42,47 +42,84 @@ class PMLCode::Updater
42
42
  end
43
43
 
44
44
  def initialize(options)
45
- @pml = options.pml
45
+ @source = options.source
46
46
  @options = options
47
47
  @current_prefix = nil
48
48
  @wrote = {}
49
+ @files = {}
49
50
  end
50
51
 
51
52
  def embeds
52
53
  @embeds ||= begin
53
- doc = Nokogiri::XML(File.read(@pml))
54
- doc.css('embed')
54
+ doc = Nokogiri::XML(File.read(@source.path))
55
+ doc.css('embed').select do |embed|
56
+ if @source.line
57
+ embed.line == @source.line
58
+ else
59
+ true
60
+ end
61
+ end
55
62
  end
56
63
  end
57
64
 
58
- def log(location, text)
59
- $stderr.puts "#{location}#{text}"
60
- end
61
-
62
65
  def run
63
66
  embeds.each do |embed|
64
- location = File.basename(@pml) + ":#{embed.line}:"
67
+ puts Rainbow(File.basename(@source.path) + ":#{embed.line} ").bold.underline
65
68
  match = @options.pattern.match(embed[:file])
66
69
  if match
67
- dedup(location, match) { update(match) }
70
+ text = dedup(match) { |already_wrote| update(match, already_wrote) }
71
+ if text
72
+ print Rainbow("OK").green
73
+ puts " : FILE #{embed[:file]} #{write_flag}"
74
+ check_part!(text, embed[:part])
75
+ else
76
+ print Rainbow("ERROR").red
77
+ puts " : FILE #{embed[:file]}"
78
+ end
68
79
  else
69
- log location, "NOMATCH #{embed[:file]}"
80
+ print Rainbow("BAD MATCH").red
81
+ puts " : FILE #{embed[:file]}"
70
82
  end
83
+ puts
71
84
  end
72
85
  end
73
86
 
74
- def dedup(location, match, &block)
75
- id = generate_update_id(match)
76
- if @wrote[id]
77
- log location, "SKIP #{id} (WROTE by #{@wrote[id][0..-2]})"
78
- else
79
- if block.()
80
- @wrote[id] = location
81
- log location, "WROTE #{id}"
87
+ def dedup(match, &block)
88
+ update_id = generate_update_id(match)
89
+ content_id = generate_content_id(match)
90
+ @files[content_id] ||= block.(@wrote[update_id])
91
+ @wrote[update_id] = true
92
+ @files[content_id]
93
+ end
94
+
95
+ def check_part!(text, part)
96
+ content = PMLCode::Content.parse(text)
97
+ if part
98
+ if content.has_part?(part)
99
+ print Rainbow("OK").green
82
100
  else
83
- log location, "INVALID #{id}"
101
+ print Rainbow("MISSING").red
84
102
  end
103
+ else
104
+ print Rainbow("--").gray
85
105
  end
106
+ puts " : PART #{part}"
107
+ puts "\n"
108
+ if @options.content
109
+ puts PMLCode::Display.new(content, part, @options)
110
+ end
111
+ end
112
+
113
+ def write_flag
114
+ if @options.dry_run
115
+ Rainbow(" DRY RUN ").green.inverse
116
+ else
117
+ Rainbow(" WRITTEN ").yellow.inverse
118
+ end
119
+ end
120
+
121
+ def generate_content_id(match)
122
+ match.string
86
123
  end
87
124
 
88
125
  def generate_update_id(match)
@@ -6,15 +6,21 @@ class PMLCode::FullUpdater < PMLCode::Updater
6
6
 
7
7
  private
8
8
 
9
- def update(match)
9
+ def update(match, already_wrote)
10
10
  full_path = directory(match)
11
11
  FileUtils.mkdir_p(full_path)
12
12
  success = false
13
+ content = nil
13
14
  Dir.chdir(@options.app) do
14
- system "git archive '#{match[:chapter]}.#{match[:snapshot]}' | tar -x -C '#{full_path}'"
15
- success = $?.success?
15
+ content = `git show origin/#{match[:chapter]}.#{match[:snapshot]}:#{match[:path]}`
16
+ if already_wrote || @options.dry_run
17
+ success = true
18
+ else
19
+ system "git archive '#{match[:chapter]}.#{match[:snapshot]}' | tar -x -C '#{full_path}'"
20
+ success = $?
21
+ end
16
22
  end
17
- success
23
+ success ? content : nil
18
24
  end
19
25
 
20
26
  def generate_update_id(match)
@@ -1,5 +1,3 @@
1
- require 'fileutils'
2
-
3
1
  class PMLCode::SparseUpdater < PMLCode::Updater
4
2
 
5
3
  handles do |criteria|
@@ -8,7 +6,7 @@ class PMLCode::SparseUpdater < PMLCode::Updater
8
6
 
9
7
  private
10
8
 
11
- def update(match)
9
+ def update(match, already_wrote)
12
10
  success = false
13
11
  content = nil
14
12
  Dir.chdir(@options.app) do
@@ -16,12 +14,14 @@ class PMLCode::SparseUpdater < PMLCode::Updater
16
14
  success = $?.success?
17
15
  end
18
16
  if success
19
- full_path = File.join(directory(match), match[:path])
20
- FileUtils.mkdir_p(File.dirname(full_path))
21
- File.open(full_path, 'w') do |f|
22
- f.write(content)
17
+ unless already_wrote || @options.dry_run
18
+ full_path = File.join(directory(match), match[:path])
19
+ FileUtils.mkdir_p(File.dirname(full_path))
20
+ File.open(full_path, 'w') do |f|
21
+ f.write(content)
22
+ end
23
23
  end
24
- true
24
+ content
25
25
  end
26
26
  end
27
27
 
@@ -1,3 +1,3 @@
1
1
  module PMLCode
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/pmlcode.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
 
23
23
  spec.add_runtime_dependency 'nokogiri', '~> 1.8', '>= 1.8.0'
24
+ spec.add_runtime_dependency 'rainbow', '~> 2.2'
24
25
 
25
26
  spec.add_development_dependency "bundler", "~> 1.15"
26
27
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pmlcode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruce Williams
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 1.8.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: rainbow
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.2'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.2'
33
47
  - !ruby/object:Gem::Dependency
34
48
  name: bundler
35
49
  requirement: !ruby/object:Gem::Requirement
@@ -91,6 +105,9 @@ files:
91
105
  - exe/pmlcode
92
106
  - lib/pmlcode.rb
93
107
  - lib/pmlcode/cli.rb
108
+ - lib/pmlcode/content.rb
109
+ - lib/pmlcode/display.rb
110
+ - lib/pmlcode/source.rb
94
111
  - lib/pmlcode/updater.rb
95
112
  - lib/pmlcode/updaters/full_updater.rb
96
113
  - lib/pmlcode/updaters/sparse_updater.rb