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 +4 -4
- data/README.md +9 -5
- data/lib/pmlcode.rb +8 -2
- data/lib/pmlcode/cli.rb +22 -8
- data/lib/pmlcode/content.rb +98 -0
- data/lib/pmlcode/display.rb +31 -0
- data/lib/pmlcode/source.rb +25 -0
- data/lib/pmlcode/updater.rb +56 -19
- data/lib/pmlcode/updaters/full_updater.rb +10 -4
- data/lib/pmlcode/updaters/sparse_updater.rb +8 -8
- data/lib/pmlcode/version.rb +1 -1
- data/pmlcode.gemspec +1 -0
- metadata +18 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7c9d54c8aff1abb04b6b9c83b086c937cc95faa
|
4
|
+
data.tar.gz: 05225b9edfdfa6ea2eeff33bca12b24bea7e5098
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,
|
27
|
-
|
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
|
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
|
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
|
-
|
85
|
+
sources = prepare(options, parser, args)
|
84
86
|
|
85
|
-
|
86
|
-
options.
|
87
|
-
options.output = File.dirname(
|
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
|
-
|
123
|
-
missing =
|
124
|
+
sources = args.map { |pml| PMLCode::Source.parse(pml) }
|
125
|
+
missing = sources.select(&:missing?)
|
124
126
|
unless missing.empty?
|
125
|
-
$stderr.puts "PML
|
127
|
+
$stderr.puts "PML sources #{missing} not found"
|
126
128
|
puts parser
|
127
129
|
exit
|
128
130
|
end
|
129
|
-
|
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
|
data/lib/pmlcode/updater.rb
CHANGED
@@ -42,47 +42,84 @@ class PMLCode::Updater
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def initialize(options)
|
45
|
-
@
|
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(@
|
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
|
-
|
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(
|
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
|
-
|
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(
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
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
|
-
|
15
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
24
|
+
content
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/lib/pmlcode/version.rb
CHANGED
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.
|
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
|