pmlcode 0.1.1 → 0.2.0

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.
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