File Coverage

blib/lib/Dita/GB/Standard.pm
Criterion Covered Total %
statement 150 164 91.4
branch 32 58 55.1
condition 15 33 45.4
subroutine 30 30 100.0
pod 14 18 77.7
total 241 303 79.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #-------------------------------------------------------------------------------
3             # The Gearhart-Brenan Dita Topic Naming Standard
4             # Philip R Brenan at gmail dot com, Appa Apps Ltd Inc., 2019
5             #-------------------------------------------------------------------------------
6             # podDocumentation
7             package Dita::GB::Standard;
8             our $VERSION = 20190901;
9             require v5.16;
10 1     1   876 use warnings FATAL => qw(all);
  1         9  
  1         41  
11 1     1   5 use strict;
  1         2  
  1         32  
12 1     1   6 use Carp qw(confess);
  1         2  
  1         78  
13 1     1   518 use Data::Dump qw(dump);
  1         7400  
  1         72  
14 1     1   2382 use Data::Table::Text qw(:all);
  1         117296  
  1         2896  
15 1     1   30 use utf8;
  1         7  
  1         25  
16              
17 12     12 0 185 sub useWords{0} #r Use word representation of md5 sum if true
18              
19             # Each word is 5 characters long so we can gain 5 bits per word using capitalization. There are 2177 words below or 11 bits - enough room to reach 16 bits per word with the 5 extra from capitalization.
20             my @words = qw(aback abate abbey abhor abide abort about above abuse abyss acorn acrid actor acute adage adapt adept admit adobe adopt adore adorn adult affix after again agent agile aging agony agree ahead aisle alarm album aleck alert algae alias alibi alien align alike alive allah allay alley allot allow alloy aloft aloha alone along aloof aloud altar alter amass amaze amber amble amend amiss among ample amply amuse angel anger angle anglo angry angst ankle annex annoy annul anvil apart apple apply april apron aptly ardor arena argue aries arise armed armor aroma arose array arrow arson artsy ashen ashes asian aside askew asset atlas attic audio audit aural avail avert avoid await awake award aware awash awful awoke axiom bacon badge badly bagel baggy baker balls balmy banal bandy bangs banjo barge baron bases basic basin basis batch bated bathe baton bawdy bayou beach beady beard beast bebop beech beefy befit began begin begun beige being belch belie belly below bench beret berry berth beset bible bigot biker billy bimbo binge bingo biped birch birth bison black blade blame bland blank blare blase blast blaze bleak bleed blend bless blimp blind blink bliss blitz block blond blood bloom blown blues bluff blunt blurb blurt blush board boast bogus bongo bonus booby books boost booth booty booze bored borne bosom bossy botch bough bound bowel boxer brace braid brain brake brand brash brass brave bravo brawl brawn bread break breed bribe brick bride brief brine bring brink briny brisk broad broil broke brood brook broom broth brown brunt brush brute buddy budge buggy bugle build built bulge bulky bully bumps bumpy bunch bunny burly burnt burst bushy butte buxom buyer bylaw byway cabby cabin cable cache cacti cadet cadre caged cagey camel cameo canal candy canny canoe caper carat cards cargo carne carol carry carte carve caste catch cater catty cause cease cedar cello chafe chain chair chalk champ chant chaos chaps charm chart chase chasm cheap cheat check cheek cheer chess chest chewy chick chide chief child chili chill chime chimp china chink chirp choir choke chord chore chose chuck chump chunk churn chute cider cigar cinch circa civic civil clack claim clamp clang clank clash clasp class claus clean clear cleat cleft clerk click cliff climb cling clink cloak clock clone close cloth cloud clout clove clown clubs cluck clump clung clunk coach coals coast cobra cocky cocoa colic colon color comet comfy comic comma condo coral corny corps cotta couch cough could count court cover covet cower crack craft cramp crane crank craps crash crass crate crave crawl craze crazy creak cream credo creed creek creep crepe crept crest crick crime crimp crisp croak crock crony crook croon cross crowd crown crude cruel crumb crush crust crypt cubic curio curly curry curse curve curvy cycle cynic daddy daily dairy daisy dally dance dandy darts dated daunt dazed dealt death debit debug debut decaf decal decay decor decoy decry defer deign deity delay delta delve demon denim dense depot depth derby deter detox devil diary dicey digit dimly diner dingy dirty disco ditch ditto ditty diver dixie dizzy dodge doggy dogma dolly donna donor dopey dorky doubt dough douse dowdy downy dowry dozen drabs draft drain drake drama drank drape drawl drawn dread dream dregs dress dribs dried drier drift drill drink drive droll drone drool droop drops drove drown drunk dryer dryly dummy dumpy dunce dusty dutch dwarf dwell dwelt dying eager eagle early earth easel eaten eater eaves ebony edict edify eerie eight eject elbow elder elect elegy elfin elite elope elude elves embed ember emcee emery empty enact endow enemy enjoy ensue enter entry envoy epoch equal equip erase erect erode error erupt essay ether ethic evade event every evict evoke exact exalt excel exert exile exist expel extol extra exude exult facet faint fairy faith false famed fancy fanny farce fatal fated fatty fault fauna favor feast fecal feces feign feint felon fence ferry fetal fetch fetid fetus fever fiber field fiend fiery fifth fifty fight filch filet filly filmy filth final finch first fishy fixed fizzy fjord flail flair flake flaky flame flank flare flash flask fleck fleet flesh flick flier fling flint flirt float flock flood floor flora floss flour flout flown fluff fluid fluke flung flunk flush flute foamy focal focus foggy foist folks folly foray force forge forgo forte forth forty forum found foyer frail frame franc frank fraud freak fresh friar fried fries frill frisk frizz frond front frost froth frown froze fruit fudge fully fumes funds fungi funky funny furor furry fussy fuzzy gabby gable gaffe gaily games gamut gassy gaudy gauge gaunt gauze gavel gawky geeky geese genre genus getup ghost ghoul giant giddy girth given gizmo glade gland glare glass glaze gleam glean glide glint glitz gloat globe gloom glory gloss glove gnash gnome godly gofer going golly goner gonna goods goody gooey goofy goose gorge gotta gouge gourd grace grade graft grain grand grant grape graph grasp grass grate grave gravy graze great greed greek green greet grief grill grime grimy grind gripe grits groan groin groom grope gross group grove growl grown gruel gruff grunt guard guess guest guide guild guile guilt guise gulch gully gumbo gummy gushy gusto gusty gutsy gypsy habit hairy halve handy happy hardy harem harsh haste hasty hatch hated haunt haven havoc hazel heads heady heard heart heave heavy hedge heels hefty heist hello hence heron hertz hiker hilly hindu hinge hippo hitch hives hoard hobby hoist hokey holly homer homey honey honor hoops horde horny horse hotel hotly hound hours house hovel hover howdy huffy human humid humor hunch hurry husky hutch hyena hyper icing ideal idiom idiot igloo image imbue impel imply inane incur index inept inert infer inlet inner input inter inuit irate irish irony islam issue itchy ivory jaded jaunt jazzy jeans jelly jerky jesus jetty jewel jiffy jinks johns joint joker jolly jowls judge juice juicy jumbo jumpy junta juror kaput karat karma kayak kelly khaki kiddo kinky kiosk kitty klutz knack knead kneel knelt knife knock knoll known koala koran kudos label labor laden ladle lance lanky lapel lapse large larva laser lasso latch later latex latin laugh layer leafy leaky leapt learn lease leash least leave ledge leech leery legal leggy legit lemon leper letup levee level lever libel libra light liken lilac limbo limit lined linen liner lines lingo lists liter lithe liven liver lives livid llama loads loath lobby local lodge lofty logic loner looks loony loose loser louse lousy lover lower lowly loyal lucid lucky lumpy lunar lunch lunge lurch lurid lusty lying lynch lyric macho macro madam madly mafia magic major maker mange mango mangy mania manic manly manor maori maple march mardi marks marry marsh mason masse match mater matte mauve maxim maybe mayor mccoy means meant meaty mecca medal media melee melon mercy merge merit merry messy metal meter metro midst might miles milky mimic mince miner minor minty minus mirth miser misty mixed mixer modal model modem moist molar moldy momma mommy money month mooch moody moose moped moral mores moron morse mossy motel motif motor motto mound mount mourn mouse mousy mouth mover movie mower mucus muddy muggy mulch mumbo mummy mumps munch mural murky mushy music musty muted muzak naive naked nanny nappy nasal nasty naval navel needs needy negro neigh nerdy nerve never newly newsy niche niece nifty night ninth nippy noble nobly noise noisy nomad noose north notch noted notes novel nudge nurse nutty nylon nymph oases oasis obese occur ocean oddly offer often oiled olden oldie olive onion onset opera opium optic orbit order organ oscar other otter ought ounce outdo outer ovary overt owing owner oxide ozone paddy padre pagan pager pages pains paint palsy panda panel panic pansy pants papal paper parka parts party passe pasta paste pasty patch patio patty pause payee peace peach pearl pecan pedal peeve penal penny peppy perch peril perky pesky petal peter petty phase phone phony photo piano picky piece piety piggy pilot pinch pinup pious pique pitch pithy pivot pixel pixie pizza place plaid plain plane plank plant plate plaza plead pleat plume plump plunk plush pluto poach point poise poker polar polio polka polls polyp pooch poppy porch posse potty pouch pound power prank prawn preen press price prick pride prima prime primp print prior prism privy prize probe promo prone prong proof prose proud prove prowl proxy prude prune psalm psych pubic pudgy puffy pulse punch pupil puppy puree purge purse pushy pussy putty pygmy pylon pyrex quack quail quake qualm quark quart quash queen queer quell query quest quick quiet quill quilt quirk quite quits quota quote rabbi rabid radar radii radio radon rains rainy raise rally ranch range ranks rapid raspy ratio raven rayon razor reach react ready realm rebel rebut recap recur redid refer regal rehab reign relax relay relic remit renew repay repel reply rerun resin retch revel revue rhino rhyme rider ridge rifle right rigid rigor rinse ripen risen riser risky ritzy rival river rivet roach roast robin robot rocky rodeo rogue roman roomy roost roots rotor rouge rough round rouse route rowdy royal ruddy rugby ruler rummy rumor runny rural rusty saber sadly saint salad sales salon salsa salty salve sandy santa sassy satan satin sauce saucy sauna saute saver savor savvy scads scald scale scalp scaly scant scare scarf scary scene scent scoff scold scoop scoot scope score scorn scour scout scowl scram scrap screw scrub scuba scuff sedan seedy seize sense serum serve setup seven sever sewer shack shade shady shaft shake shaky shall shame shape share shark sharp shave shawl sheaf shear sheen sheep sheer sheet sheik shelf shell shift shine shiny shirk shirt shoal shock shone shook shoot shore shorn short shout shove shown showy shred shrub shrug shuck shunt shush shyly sidle siege sieve sight silky silly since sinew singe sinus siren sissy sixth sixty skate skier skill skimp skirt skull skunk slack slain slake slang slant slash slate slave sleek sleep sleet slept slice slick slide slime slimy sling slink slope slosh sloth slump slung slunk slurp slush slyly smack small smart smash smear smell smile smirk smith smock smoke smoky snack snafu snail snake snare snarl sneak sneer snide sniff snipe snoop snore snort snout snowy snuck snuff soapy sober softy soggy solar solid solve sonic sorry sound south space spade spank spare spark spasm spate spawn speak spear speck speed spell spelt spend spent spice spicy spiel spike spill spine spire spite splat splay split spoil spoke spoof spook spool spoon sport spout spray spree sprig spurn spurt squad squat squid stack staff stage staid stain stair stake stale stalk stall stamp stand stank stare stark stars start stash state stave steak steal steam steel steep steer stern stick stiff still stilt sting stink stint stock stoic stoke stole stomp stone stony stood stool stoop store stork storm story stout stove strap straw stray strep strew strip strum strut stuck study stuff stump stung stunk stunt style suave suede sugar suite sulky sunny sunup super surge surly swamp swank swarm swear sweat sweep sweet swell swept swift swine swing swipe swirl swish swiss swoon swoop sword swore sworn swung synod syrup tabby table taboo tacit tacky taffy tails taint taken talks tally talon tango tangy taper tardy tarot tarry taste tasty taunt tawny teach tease teddy teens teeth tempo tempt tenet tenor tense tenth tepee tepid terms terra terse testy thank theft their theme there these thick thief thigh thing think third thong thorn those three threw throb throw thumb thump tiara tidal tiger tight timer times timid tinge tinny tipsy tired title tizzy toast today toefl token tongs tonic tooth topic torch torso total totem touch tough towel tower toxic toxin trace track tract trade trail train trait tramp trash trawl tread treat trend trial tribe trick trike trill tripe trite troll tromp troop trout truce truck truly trump trunk trust truth tubby tulip tummy tumor tuner tunic tutor twang tweak tweed tweet twerp twice twine twirl twist udder ulcer uncle uncut under undid undue unfit unify union unite unity untie until unzip upend upper upset urban usage usher usual usurp uteri utter vague valet valid valor value valve vapor vault vegan venom venue venus verge versa verse verve vibes video vigil vigor villa vinyl viola viper viral virgo virus visit visor vista vital vivid vocal vodka vogue voice vomit voter vouch vowel wacky wafer wager wages wagon waist waive waken waltz wanna wares waste watch water waver weary weave wedge weigh weird welsh whack whale wharf wheat wheel where which whiff while whine whirl whisk white whole whoop whose widen widow width wield wiles wimpy wince winch windy wings wiper wired wispy witch witty wives woken woman women woods woody wooly woozy words wordy works world worms worry worse worst worth would wound woven wrath wreak wreck wrest wring wrist write wrong wrote wrung wryly xerox yacht yearn years yeast yield yodel yokel young yours youth yucky yummy zebra);
21              
22             !useWords or @words > 2**11 or confess "Not enough words";
23              
24             sub hex4ToBits($) #P Represent 4 hex digits as (1, 1, 1, 1, 1, 12) bits
25 19     19 0 49 {my ($h) = @_;
26 19         40 my $n = hex($h);
27 19         29 my $n11 = $n % 2**11;
28 19         35 my $n12 = ($n>>11) % 2;
29 19         29 my $n13 = ($n>>12) % 2;
30 19         26 my $n14 = ($n>>13) % 2;
31 19         28 my $n15 = ($n>>14) % 2;
32 19         29 my $n16 = ($n>>15) % 2;
33 19         71 ($n16, $n15, $n14, $n13, $n12, $n11);
34             }
35              
36             sub hexAsWords($) #P Given a hex string represent it as words at a rate of 16 bits per word
37 11     11 0 26 {my ($hex) = @_;
38              
39 11         22 my $d = length($hex) % 4;
40 11 50       27 $hex .= '0' x (4-$d) if $d;
41              
42 11         17 my @w;
43              
44 11         34 for my $p(1..length($hex) / 4) # Each block of hex representing 16 bits
45 11         36 {my ($a, $b, $c, $d, $e, $r) = hex4ToBits(substr($hex, 4*($p-1), 4));
46 11         29 my $w = $words[$r];
47 11 100       24 $w = uc(substr($w, 0, 1)).substr($w, 1) if $a;
48 11 100       24 $w = substr($w, 0, 1).uc(substr($w, 1, 1)).substr($w, 2) if $b;
49 11 100       26 $w = substr($w, 0, 2).uc(substr($w, 2, 1)).substr($w, 3) if $c;
50 11 100       28 $w = substr($w, 0, 3).uc(substr($w, 3, 1)).substr($w, 4) if $d;
51 11 100       18 $w = substr($w, 0, 4).uc(substr($w, 4, 1)).substr($w, 5) if $e;
52 11         32 push @w, $w;
53             }
54              
55 11         69 join '_', @w;
56             }
57              
58             #D1 Make and manage utf8 files # Make and manage files that conform to the L and are coded in utf8.
59              
60             sub gbStandardFileName($$%) #E Return the L file name given the content and extension of a proposed file.
61 5     5 1 53 {my ($content, $extension, %options) = @_; # Content, extension, various ingenious options designed by Micaela
62 5 50       26 defined($content) or confess "Content must be defined";
63 5         44 $content =~ s(\s*xtr[cf]="[^"]*") ()gs; # Suppress xtrc|f attributes as we use them to hold file names and line numbers during a conversion but they are not germane to the final result and thus prevent files from being collapsed.
64              
65 5 50 33     72 $extension && ($extension =~ m(\A\S{2,}\Z)s) or
66             confess "Extension must be non blank and at least two characters long";
67 5   100     51 my $name = $options{g} || nameFromStringRestrictedToTitle($content, %options);# Human readable component either as supplied in exceptional cases, or ideally, as taken from the title tag according to the prescription of the Monroe Title Method.
68 5   33     26924 my $md5 = $options{md5} // fileMd5Sum($content); # Md5 sum either as supplied or computed
69              
70 5 50 66     9427 fpe($name.q(_).(&useWords ? hexAsWords($md5) : $md5), # Add extension
71             fe($extension)||$extension); # fe returns blank given an extension name without a .
72             }
73              
74             sub gbStandardCompanionFileName($) #E Return the name of the L given a file whose name complies with the L.
75 12     12 1 40 {my ($file) = @_; # L file name
76 12         54 setFileExtension($file); # Remove extension to get companion file name
77             }
78              
79             sub gbStandardCompanionFileContent($) #E Return the content of the L given a file whose name complies with the L.
80 2     2 1 13 {my ($file) = @_; # L file name
81 2         12 readFile(gbStandardCompanionFileName($file)) # L companion file name content
82             }
83              
84             sub gbStandardCreateFile($$$%) #E Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>
85 1     1 1 42 {my ($Folder, $content, $extension, %options) = @_; # Target folder or a file in that folder, content of the file, file extension, options.
86 1         27 my $folder = fp $Folder; # Normalized folder name
87 1         72 my $file = gbStandardFileName($content, $extension, %options); # Entirely satisfactory
88              
89 1         86 my $out = fpf($folder, $file); # Output file
90 1         91 overWriteFile($out, $content); # Write file content
91              
92 1 50       495 if (my $content = $options{companionContent}) # Write a companion file if some content for it has been supplied
93 1         8 {my $comp = gbStandardCompanionFileName($out); # Companion file name
94 1 50       54 if (!-e $comp) # Do not overwrite existing companion file
95 1         19 {writeFile($comp, $content); # Write companion file
96             }
97             else
98 0         0 {confess "Companion file already exists:\n$comp\n";
99             }
100             }
101             $out
102 1         245 }
103              
104             sub gbStandardRename($%) #E Check whether a file needs to be renamed to match the L. Return the correct name for the file or B if the name is already correct.
105 2     2 1 8 {my ($file, %options) = @_; # File to check, options
106 2         8 my $content = readFile($file); # Content of proposed file
107 2         348 my $ext = fe($file); # Extension of proposed file
108 2         50 my $proposed = gbStandardFileName($content, $ext, %options); # Proposed name according to the L
109 2         92 my $base = fne($file); # The name of the current file minus the path
110 2 50       42 return undef if $base eq $proposed; # Success - the names match
111 0         0 $proposed # Fail - the name should be this
112             }
113              
114             sub gbStandardCopyFile($%) #E Copy a file to the specified B<$target> folder renaming it to the L. If no B<$Target> folder is specified then rename the file in its current folder so that it does comply with the L.
115 1     1 1 12 {my ($source, %options) = @_; # Source file, options
116 1 50 33     46 -e $source && !-d $source or # Check that the source file exists and is a file
117             confess "Source file to normalize does not exist:\n$source";
118              
119 1         5 my $target = $options{target}; # The target folder (or a file in it) to which to copy this file
120 1         6 my $correctName = gbStandardRename($source, %options); # Get the correct name for the file
121              
122 1 50 33     14 if ($target and $target ne fp($source)) # New target folder specified
    0          
123 1   33     34 {my $t = fpf($target, fne($correctName//$source)); # Target of copy
124 1         47 copyFile($source, $t); # Copy file
125 1         580 my $cs = gbStandardCompanionFileName($source); # Companion file source
126 1         13 my $ct = gbStandardCompanionFileName($t); # Companion file target
127 1 50       20 if (-e $cs) # Copy companion source file if it exists
128 1         6 {copyFile($cs, $ct); # Copy companion source file
129             }
130             else # Create companion target file if it does not exist
131 0         0 {dumpFile($ct, {source=>$source}); # Write source file name to companion file target
132             }
133 1         440 return $t;
134             }
135             elsif ($correctName) # Rename file to match L
136 0         0 {my $t = fpf(fp($source), fne $correctName); # Full file name
137 0         0 rename $source, $t; # Rename file so it matches L
138 0         0 return $t;
139             }
140             undef
141 0         0 }
142              
143             sub gbStandardDelete($) #E Delete a file and its companion file if there is one.
144 1     1 1 38 {my ($file) = @_; # File to delete
145 1         6 my $comp = gbStandardCompanionFileName($file);
146 1         120 unlink $_ for $comp, $file;
147             }
148              
149             #D1 Make and manage binary files # Make and manage files that conform to the L and are in plain binary.
150              
151             sub gbBinaryStandardFileName($$) #E Return the L file name given the content and extension of a proposed file.
152 4     4 1 38 {my ($content, $extension) = @_; # Content, extension
153 4 50       33 defined($content) or confess "Content must be defined";
154              
155 4   66     43 my $e = fe($extension) || $extension; # File extension - if given an extension without a leading . fe will return blank
156 4 50       139 $e =~ m(\A\S{2,}\Z)s or
157             confess "Extension must be non blank and at least two characters long: ".
158             dump([$e, $extension]);
159 4         16 my $name = lc $e; # Human readable component was taken from the file content but this produced long garbled names as there was no useful ascii content at the start of most image files. Substituted the extension lower case instead to separate the images out in directory listings.
160 4         34 my $md5 = fileMd5Sum($content); # Md5 sum
161 4 50       7129 fpe($name.q(_).(&useWords ? hexAsWords($md5) : $md5), $e) # Add extension
162             }
163              
164             sub gbBinaryStandardCompanionFileName($) #E Return the name of the companion file given a file whose name complies with the L.
165 7     7 1 24 {my ($file) = @_; # L file name
166 7         29 setFileExtension($file); # Remove extension to get companion file name
167             }
168              
169             sub gbBinaryStandardCompanionFileContent($) #E Return the content of the L given a file whose name complies with the binary L.
170 2     2 1 8 {my ($file) = @_; # L file name
171 2         16 readFile(gbStandardCompanionFileName($file)) # L companion file name content
172             }
173              
174             sub gbBinaryStandardCreateFile($$$;$) #E Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>.
175 1     1 1 20 {my ($Folder, $content, $extension, $companionContent) = @_; # Target folder or a file in that folder, content of the file, file extension, contents of the companion file.
176 1         33 my $folder = fp $Folder; # Normalized folder name
177 1         64 my $file = gbBinaryStandardFileName($content, $extension); # Entirely satisfactory
178              
179 1         59 my $out = fpf($folder, $file); # Output file
180 1         45 overWriteBinaryFile($out, $content); # Write file content
181              
182 1 50       467 if (defined $companionContent) # Write a companion file if some content for it has been supplied
183 1         10 {my $comp = gbBinaryStandardCompanionFileName($out); # Companion file name
184 1 50       64 if (!-e $comp) # Do not overwrite existing companion file
185 1         17 {writeBinaryFile($comp, $companionContent); # Write companion file
186             }
187             else
188 0         0 {confess "Companion file already exists:\n$comp\n";
189             }
190             }
191             $out
192 1         189 }
193              
194             sub gbBinaryStandardRename($) #E Check whether a file needs to be renamed to match the L. Return the correct name for the file or B if the name is already correct.
195 2     2 1 13 {my ($file) = @_; # File to check
196 2         8 my $content = readBinaryFile($file); # Content of proposed file
197 2         193 my $proposed = gbBinaryStandardFileName($content, $file); # Proposed name according to the L
198 2         60 my $base = fne($file); # The name of the current file minus the path
199 2 50       43 return undef if $base eq $proposed; # Success - the names match
200 0         0 $proposed # Fail - the name should be this
201             }
202              
203             sub gbBinaryStandardCopyFile($;$) #E Copy a file to the specified B<$target> folder renaming it to the L. If no B<$Target> folder is specified then rename the file in its current folder so that it does comply with the L.
204 1     1 1 5 {my ($source, $target) = @_; # Source file, target folder or a file in the target folder
205 1 50 33     48 -e $source && !-d $source or # Check that the source file exists and is a file
206             confess "Source file to normalize does not exist:\n$source";
207 1         9 my $correctName = gbBinaryStandardRename($source); # Get the correct name for the file
208 1 50 33     12 if ($target and $target ne fp($source)) # New target folder specified
    0          
209 1   33     38 {my $t = fpf($target, fne($correctName // $source)); # Target of copy
210 1         53 copyBinaryFile($source, $t); # Copy file
211 1         378 my $cs = gbBinaryStandardCompanionFileName($source); # Companion file source
212 1         13 my $ct = gbBinaryStandardCompanionFileName($t); # Companion file target
213              
214 1 50       25 if (-e $cs) # Copy companion source file if it exists
215 1         11 {copyFile($cs, $ct); # Copy companion source file
216             }
217             else # Create companion target file if it does not exist
218 0         0 {dumpFile($ct, {source=>$source}); # Write source file name to companion file target
219             }
220 1         416 return $t;
221             }
222             elsif ($correctName) # Rename file to match L
223 0         0 {my $t = fpf(fp($source), fne $correctName); # Full file name
224 0         0 rename $source, $t; # Rename file so it matches L
225 0         0 return $t;
226             }
227             undef
228 0         0 }
229              
230             sub gbBinaryStandardDelete($) #E Delete a file and its L if there is one.
231 1     1 1 4 {my ($file) = @_; # File to delete
232 1         4 my $comp = gbBinaryStandardCompanionFileName($file);
233 1         114 unlink $_ for $comp, $file;
234             }
235              
236             #Doff
237              
238             say STDERR "gbStandard Exportable Methods:\n",
239             formatTable(reportExportableMethods($0)) if 0;
240              
241             #-------------------------------------------------------------------------------
242             # Export
243             #-------------------------------------------------------------------------------
244              
245 1     1   3990 use Exporter qw(import);
  1         4  
  1         67  
246              
247 1     1   9 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         1028  
248              
249             @ISA = qw(Exporter);
250             @EXPORT_OK = qw(
251             gbBinaryStandardCompanionFileContent
252             gbBinaryStandardCompanionFileName
253             gbBinaryStandardCopyFile
254             gbBinaryStandardCreateFile
255             gbBinaryStandardDelete
256             gbBinaryStandardFileName
257             gbBinaryStandardRename
258             gbStandardCompanionFileContent
259             gbStandardCompanionFileName
260             gbStandardCopyFile
261             gbStandardCreateFile
262             gbStandardDelete
263             gbStandardFileName
264             gbStandardRename
265             );
266             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
267              
268             # podDocumentation
269              
270             my $nameFromStringMaximumLength = Data::Table::Text::nameFromStringMaximumLength;
271              
272             my $documentationSynopsis = <
273              
274             The L is a means of naming L topic files to enable global
275             collaboration through uncoordinated content sharing.
276              
277             The L creates a human readable, deterministic file name which
278             depends solely on the content to be stored in that file. Such file names are
279             guaranteed to differ between files that contain differing content while being
280             identical for files that contain identical content by the use of an L in
281             the file name.
282              
283             The L name looks like this:
284              
285             human_readable_part_derived_from_content + _ + md5_sum_of_content + extension
286              
287             The human readable part from content is derived solely from the content of the
288             file by interpreting the file content as L encoded as L, then:
289              
290             - replacing instances of xml tags with underscores
291              
292             - replacing all characters other than a-z,A-Z,0-9 with underscores
293              
294             - replacing runs of underscores with a single underscore
295              
296             - removing any leading or trailing underscores
297              
298             - truncating the component if it extends beyond $nameFromStringMaximumLength characters.
299              
300             The original file name for the content is not considered as part of the content
301             of the file and so plays no part in choosing the L name for that
302             content.
303              
304             If the file contains a B tag then only the content of the B<title> tag </td> </tr> <tr> <td class="h" > <a name="305">305</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> is processed as described above to obtain the human readable component of the </td> </tr> <tr> <td class="h" > <a name="306">306</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> file name. If any of the following L<Dita> tags are found in a source file </td> </tr> <tr> <td class="h" > <a name="307">307</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> which also contains a B<title> tag then the following codes are prefixed to </td> </tr> <tr> <td class="h" > <a name="308">308</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> this file name as well: </td> </tr> <tr> <td class="h" > <a name="309">309</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="310">310</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Code Tag </td> </tr> <tr> <td class="h" > <a name="311">311</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> bm_ bookmap </td> </tr> <tr> <td class="h" > <a name="312">312</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> c_ concept </td> </tr> <tr> <td class="h" > <a name="313">313</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> r_ reference </td> </tr> <tr> <td class="h" > <a name="314">314</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> t_ task </td> </tr> <tr> <td class="h" > <a name="315">315</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="316">316</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The L<md5> component of the file name is calculated from the content of the </td> </tr> <tr> <td class="h" > <a name="317">317</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> file and presented as lowercase hexadecimal. </td> </tr> <tr> <td class="h" > <a name="318">318</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="319">319</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The file extension component is obtained from: </td> </tr> <tr> <td class="h" > <a name="320">320</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<https://en.wikipedia.org/wiki/List_of_filename_extensions> </td> </tr> <tr> <td class="h" > <a name="321">321</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="322">322</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Thus if a B<dita> file has content: </td> </tr> <tr> <td class="h" > <a name="323">323</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="324">324</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <concept> </td> </tr> <tr> <td class="h" > <a name="325">325</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <title>abc 𝝰𝝱𝝲
326            
327            
328              
329             then the L name for the file is:
330              
331             c_abc_8551cffdb92932637d952e04447783c8.dita
332              
333             If the option to present the L as five letter English words is chosen
334             then the standardized name for this content becomes:
335              
336             c_abc_Plume_VApoR_CaPER_eqUAl_qUAIL_saInT_mEdia_Irony.dita
337              
338             `head2 Benefits
339              
340             The file names generated by the L can be exploited in numerous ways
341             to simplify the creation, conversion, management and sharing of large
342             repositories of documents written to the L standard:
343              
344             `head3 Parallel Processing
345              
346             Complex long running document transformations can be speeded up by running the
347             transformations in parallel.
348              
349             The file name generated by the L is unique when computed by
350             competing parallel processes so files that have the same name have the same
351             content and can be safely overwritten by another process without attempting to
352             coordinate names between processes. Likewise files that have different names
353             are guarenteed to have different content and so can be written out without
354             checking for an existing file of that name.
355              
356             Alternative systems relying on coordination between the parallel processes to
357             choose names to avoid collisions and reuse identical content perform ever more
358             badly as the number of files increases because there are ever more files to
359             check for matching content and names. Coordination between parallel processes
360             stops the processes from running fully in parallel. Conversely, eliminating the
361             need for coordination between parallel processes allows each process to run
362             more fully in parallel.
363              
364             As a consequence, the L enables parallel L conversions to
365             scale effectively.
366              
367             `head3 File Flattening
368              
369             Files are automatically flattened by the L as files with the same
370             content have the same name and so can safely share one global folder without
371             fear of name collisions or having multiple names for identical content.
372              
373             `head3 Testing
374              
375             The name of each file reflects only its content making it easier to write tests
376             for software build around the L: it is no longer necessary to test
377             that the content of the file is as expected when it is sufficent just to test
378             the base name of the file.
379              
380             One could, of course, compute the L of the file easily during testing
381             but: the fact that one is computing such a sum at all shows just how useful
382             such a sum is, which implies that it should be the one and only piece of meta
383             data encoded in the file name. All othermeta data should reside within the
384             file rather then being encoded in the file name so that said meta data is not
385             destroyed by renaming the file.
386              
387             `head3 Mixed Multiple Conversions
388              
389             When converting documents to L it is a standard practice to perform the
390             conversion in batches by source document type, perhaps B files first, then
391             B files, then L files. Thus leaves the problem of merging the
392             results into one corpus after each individual conversion. The L
393             resolves this problem by guaranteeing the uniqueness of the converted
394             files allowing them to be merged into one results folder without collisions.
395              
396             `head3 No Relative Paths in References
397              
398             If all the topic files share one global folder there is no need for complicated
399             path expressions in references such as:
400              
401            
402              
403             Extended path names that are repeated across many references are, in effect, a
404             form of boiler plate which can be avoided by applying this standard.
405              
406             `head3 Relocating Dita References After Folder Restructuring
407              
408             In the ideal implementation all files named with the L occupy one
409             global folder. In circumstances where this is not possible, such files can
410             easily be moved into sub folders without fear of collisions, although, any Dita
411             references between such files might have to be updated. This update is easily
412             performed because only the path component has to be updated and the value of
413             the new path can easily be found by searching for the base component of the
414             topic file name using a utility such as L. For a more efficient method,
415             see L.
416              
417             `head3 Similar Files Tend To Appear Close Together In Directory Listings.
418              
419             Imagine the user has several files in different folders all starting:
420              
421             License Agreement
422              
423             The L computes the human readable component of the name in a
424             consistent way using only the contents of each file. Once the name has been
425             standardized, all these files can be placed in B folder to get a directory
426             listing like:
427              
428             license_agreement_a6e3...
429             license_agreement_b532...
430             license_agreement_c65d...
431              
432             This grouping signals that these files are potentially similar to each other
433             and thus might be better merged into one shareable file.
434              
435             As the L is applied to ever more such files, ever more such matches
436             occur.
437              
438             `head3 Copying And Moving Files For Global Interoperability
439              
440             Users can copy files named using the L around from folder to folder
441             without fear of collisions or duplication obviating the need for the time
442             consuming checks and reportage otherwise required before performing such
443             actions. The meta data in the L can also be copied in a similar
444             fearless manner.
445              
446             If two users wish to share content: their files named using the L
447             can be incorporated directly into the other user's file system without fear of
448             collisions or duplicating content thus promoting global content sharing and
449             collaboration of L content.
450              
451             `head3 Guidization For Content Management Systems
452              
453             Self constructed Content Management Systems using BitBucket, GitHub or Gitlab
454             that rely on guidization to differentiate files placed in these repositories
455             benefit immensely: the L to use can be easily derived from the L sum
456             in the L file name.
457              
458             `head3 No need for authors to coordinate topic file names
459              
460             The L is relevant to the administration of a production document
461             corpus. A production corpus being a corpus of documents that is B
462             over time under the control of an administrator.
463              
464             If an author is developing a document from scratch, in splendid isolation,
465             then, initially, the author might well wish to use topic file names of their
466             own choice to contain their topics as this will speed their efforts.
467              
468             For example, it is not uncommon for an author to create a file called:
469              
470             introduction.xml
471              
472             to hold the introduction to the new document they are writing.
473              
474             At some point the system administrator will wish to incorporate the topic files
475             comprising the new document produced by the author into the production corpus.
476              
477             The chance that any of the file names that the author has chosen will conflict
478             with the existing names in the production corpus as generated by the
479             L is negligible. It is thus safe for the administrator to copy the
480             author's topic files directly into the production corpus without renaming any
481             of them. Sooner or later, however, the administrator might wish to run an
482             automated scan of the entire production corpus to rename such recent additions
483             to the L, to update all the references between these files that
484             would otherwise be invalidated by such changes and thereby to clear the
485             production corpus to make it ready to receive other new documents whose topic
486             file names, being chosen by humans, would otherwise very likely conflict with
487             existing topic file names already in the production corpus.
488              
489             Thus clearing the production corpus by applying the L obviates the
490             need for authors to coordinate the names of the files that they choose for
491             their topics with those choosen by other authors allowing each author to
492             proceed efficiently in isolated parallelism, spending more time writing and
493             less time in meetings with other authors discussing their latest file naming
494             strategy.
495              
496             `head3 Using Dita Tags To Describe Content
497              
498             The L encourages L users to use meta data tags to describe
499             their documents so that content can be found by searching with L rather
500             than encoding file meta data in file names then searching for the required file
501             using L. Such file names quickly become very long and unmanageable: on
502             the one hand they need spaces in them to make them readable, but on the other
503             hand, the spaces make such files difficult to cut and paste or use from the
504             L.
505              
506             `head3 Cut And Paste
507              
508             As there are no spaces in the files names created using the L such
509             file names can be selected by a mouse double click and thus easily copied and
510             pasted into other documents.
511              
512             Conversely, one has to use cut and paste to manipulate such file names making
513             it impossible to mistype such file names in other documents.
514              
515             `head3 CSV files
516              
517             Files named using the L can be safely included in B<.csv> files
518             because they have no spaces in them!
519              
520             `head3 Automatic File Versioning
521              
522             Files named to the L File names change when their content changes.
523             So if the content of a file changes its name must change as well. Thus an
524             attempt to present an out-of-date version of a file produces a file name that
525             cannot be found.
526              
527             `head3 Enhanced Command Line Processing
528              
529             As file names named with the L do not have spaces in them (such as
530             L) they work well on the L and with the many
531             L tools that are used to manipulate such files enhancing the
532             productivity leverage that L has always had versus L
533             processing.
534              
535             `head3 Locating Files by Their Original Names Or Other Meta-Data
536              
537             Each file produced by the L can have a L of the same
538             name but without an extension. The L contains meta-data about the
539             file such as its original location etc. which can be searched by L or
540             similar.
541              
542             To find such a file use L to find the L containing the
543             searched for content, paste that file name into the L after
544             entering any command such as B and then press B<.> followed by the L
545             key to have the L expand it to locate the L file that
546             corresponds to the located L. For example:
547              
548             \\grep -r 'SR-dashboard-ds.png'
549              
550             png_f940c7db293fe377e7d49c4e0c654cb2: source => "/home/phil/r/pureStorage/docBook/download/OE_User_Guide/SRRBeta/images/screenshots/dashboard/SR-dashboard-ds.png",
551              
552             ls png_f940c7db293fe377e7d49c4e0c654cb2.png
553              
554             `head3 Use with AWS Simple Storage Service
555              
556             Viewing files held in L is made much easier if they are all in one flat
557             folder with uniqwue base names as there is no folder structure to navigate over
558             a nework. Simply type the start of the B part, the Human Readdable
559             Component, and press enter to see the possible candidates.
560              
561             `head2 Companion File
562              
563             Each file named using the L may be accompanied by a
564             L that contains meta data describing the file, said data
565             formatted as a L data structure.
566              
567             The name of the L is obtained by removing the extension from the
568             file named using the L.
569              
570             As the content of the companion files is in plain text, such text is easy to
571             search using L or other textual search tools.
572              
573             A common use of the companion file is to record the orginal file name and
574             author of the content in question:
575              
576             {source=>q(C:/my documents/dita files/content.dita),
577             author=>q(A. N. Mouse),
578             }
579              
580             `head2 Alternate File Names
581              
582             Most operating systems allow the use of links to supply alternate names for a
583             file. Consequently, users who wish to impose a different file naming scheme
584             might care to consider using links to implement their own file naming system on
585             top of the L without disrupting the integrity of the L.
586              
587             For example: L produces B which provide a virtual
588             hierarchical folder view of an otherwise flat folder.
589              
590             `head2 Implementation
591              
592             The L has been implemented as a L package at:
593              
594             L
595              
596             `head2 Binary vs Utf8
597              
598             Files that are expected to contain data encoded with L (eg .dita, .xml)
599             should use method names that start with:
600              
601             gbStandard
602              
603             Files that are expected to contain binary data (eg .png, .jpg) should use
604             method names that start with:
605              
606             gbBinaryStandard
607              
608             The binary standard forms file names by prefixing the L value with the
609             extension of the file in lower case and an underscore to prevent the long
610             garbled file names that would otherwise be chosen if the normal standard were
611             applied directly to naming such content and to group such files close together
612             in directory listings.
613              
614             Consequently, a B file with content:
615              
616             q(\0abc\1)
617              
618             will be represented by the name:
619              
620             png_2786f1147a331ec6ebf60c1ba636a458.png
621              
622             `head2 Documentation Copyright
623              
624             The documentation for this module is dual licensed with the L as well
625             as the L in the hope that this will encourage its further dissemination
626             as a universal standard.
627              
628             END
629              
630             my $removedSections = <
631             `head3 Using Longer Titles To Describe Content
632              
633             The L encourages L writers to choose better titles for their
634             topics. A title of B is fine as far as a single document goes,
635             the subject matter to which we are being introduced is presumably the title of
636             the containing book, perhaps: B.
637              
638             But suppose you are creating a library with millions of searchable books?
639             Problems start to arise: many other books will have introductions too; many of
640             these introductions will share similar sentiments and content. If, like
641             L, you are in the business of selling paper, this is a good thing. If you
642             are management trying to make it easy for readers to find relevant articles
643             while reducing writing costs, then a different approach might be indicated.
644              
645             A first step would be to insist that the proper topic title is more self
646             contained so it can be found in isolation:
647              
648             Introduction to the Art of Making Pasta
649              
650             and that the file that contains this topic starts with a name easily and
651             consistently derived from the title:
652              
653             Introduction_to_the_Art_of_Making_Pasta ....
654              
655             so that it can be more easily found by both readers and writers.
656              
657             A second step might be to standardize introductions as much as possible to
658             reduce their number and to enable the production of targeted variants such as:
659              
660             Introduction to the Art of Making Pasta for Beginners
661              
662             or
663              
664             Introduction to the Art of Making Pasta for Visitors from Italy
665              
666             by mixing and matching standardized content from elsewhere.
667              
668             The L facilitates both of these actions by grouping the
669             introduction files close together further differentiated by an L
670             on the right.
671              
672             An instinctive desire to push the L further to the right where it is less
673             visible encourages the writer to choose a longer more explicit and hopefully
674             unique title.
675              
676             As the file name is derived from the title it is easy for a reader to find a
677             file given the title especially when the title is unique.
678              
679             The fact that the library has millions of topics called B is made
680             abundantly clear to management when the folder holding these files is printed
681             out alphabetically, placed on their desks and they try looking for a topic
682             about B, The difficulties encountered in getting past B encourages
683             management to ask: "Why do we have so many slightly different introductions"?
684              
685             END
686              
687             =pod
688              
689             =encoding utf-8
690              
691             =head1 Name
692              
693             Dita::GB::Standard - The Gearhart-Brenan Dita Topic Naming Standard.
694              
695             =head1 Synopsis
696              
697             The L is a means of naming L topic files to enable global
698             collaboration through uncoordinated content sharing.
699              
700             The L creates a human readable, deterministic file name which
701             depends solely on the content to be stored in that file. Such file names are
702             guaranteed to differ between files that contain differing content while being
703             identical for files that contain identical content by the use of an L in
704             the file name.
705              
706             The L name looks like this:
707              
708             human_readable_part_derived_from_content + _ + md5_sum_of_content + extension
709              
710             The human readable part from content is derived solely from the content of the
711             file by interpreting the file content as L encoded as L, then:
712              
713             - replacing instances of xml tags with underscores
714              
715             - replacing all characters other than a-z,A-Z,0-9 with underscores
716              
717             - replacing runs of underscores with a single underscore
718              
719             - removing any leading or trailing underscores
720              
721             - truncating the component if it extends beyond $nameFromStringMaximumLength characters.
722              
723             The original file name for the content is not considered as part of the content
724             of the file and so plays no part in choosing the L name for that
725             content.
726              
727             If the file contains a B tag then only the content of the B<title> tag </td> </tr> <tr> <td class="h" > <a name="728">728</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> is processed as described above to obtain the human readable component of the </td> </tr> <tr> <td class="h" > <a name="729">729</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> file name. If any of the following L<Dita|http://docs.oasis-open.org/dita/dita/v1.3/os/part2-tech-content/dita-v1.3-os-part2-tech-content.html> tags are found in a source file </td> </tr> <tr> <td class="h" > <a name="730">730</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> which also contains a B<title> tag then the following codes are prefixed to </td> </tr> <tr> <td class="h" > <a name="731">731</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> this file name as well: </td> </tr> <tr> <td class="h" > <a name="732">732</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="733">733</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Code Tag </td> </tr> <tr> <td class="h" > <a name="734">734</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> bm_ bookmap </td> </tr> <tr> <td class="h" > <a name="735">735</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> c_ concept </td> </tr> <tr> <td class="h" > <a name="736">736</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> r_ reference </td> </tr> <tr> <td class="h" > <a name="737">737</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> t_ task </td> </tr> <tr> <td class="h" > <a name="738">738</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="739">739</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The L<md5 sum|https://en.wikipedia.org/wiki/MD5> component of the file name is calculated from the content of the </td> </tr> <tr> <td class="h" > <a name="740">740</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> file and presented as lowercase hexadecimal. </td> </tr> <tr> <td class="h" > <a name="741">741</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="742">742</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The file extension component is obtained from: </td> </tr> <tr> <td class="h" > <a name="743">743</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<https://en.wikipedia.org/wiki/List_of_filename_extensions> </td> </tr> <tr> <td class="h" > <a name="744">744</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="745">745</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Thus if a B<dita> file has content: </td> </tr> <tr> <td class="h" > <a name="746">746</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="747">747</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <concept> </td> </tr> <tr> <td class="h" > <a name="748">748</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <title>abc 𝝰𝝱𝝲
749            
750            
751              
752             then the L name for the file is:
753              
754             c_abc_8551cffdb92932637d952e04447783c8.dita
755              
756             If the option to present the L as five letter English words is chosen
757             then the standardized name for this content becomes:
758              
759             c_abc_Plume_VApoR_CaPER_eqUAl_qUAIL_saInT_mEdia_Irony.dita
760              
761             =head2 Benefits
762              
763             The file names generated by the L can be exploited in numerous ways
764             to simplify the creation, conversion, management and sharing of large
765             repositories of documents written to the L standard:
766              
767             =head3 Parallel Processing
768              
769             Complex long running document transformations can be speeded up by running the
770             transformations in parallel.
771              
772             The file name generated by the L is unique when computed by
773             competing parallel processes so files that have the same name have the same
774             content and can be safely overwritten by another process without attempting to
775             coordinate names between processes. Likewise files that have different names
776             are guarenteed to have different content and so can be written out without
777             checking for an existing file of that name.
778              
779             Alternative systems relying on coordination between the parallel processes to
780             choose names to avoid collisions and reuse identical content perform ever more
781             badly as the number of files increases because there are ever more files to
782             check for matching content and names. Coordination between parallel processes
783             stops the processes from running fully in parallel. Conversely, eliminating the
784             need for coordination between parallel processes allows each process to run
785             more fully in parallel.
786              
787             As a consequence, the L enables parallel L conversions to
788             scale effectively.
789              
790             =head3 File Flattening
791              
792             Files are automatically flattened by the L as files with the same
793             content have the same name and so can safely share one global folder without
794             fear of name collisions or having multiple names for identical content.
795              
796             =head3 Testing
797              
798             The name of each file reflects only its content making it easier to write tests
799             for software build around the L: it is no longer necessary to test
800             that the content of the file is as expected when it is sufficent just to test
801             the base name of the file.
802              
803             One could, of course, compute the L of the file easily during testing
804             but: the fact that one is computing such a sum at all shows just how useful
805             such a sum is, which implies that it should be the one and only piece of meta
806             data encoded in the file name. All othermeta data should reside within the
807             file rather then being encoded in the file name so that said meta data is not
808             destroyed by renaming the file.
809              
810             =head3 Mixed Multiple Conversions
811              
812             When converting documents to L it is a standard practice to perform the
813             conversion in batches by source document type, perhaps B files first, then
814             B files, then L files. Thus leaves the problem of merging the
815             results into one corpus after each individual conversion. The L
816             resolves this problem by guaranteeing the uniqueness of the converted
817             files allowing them to be merged into one results folder without collisions.
818              
819             =head3 No Relative Paths in References
820              
821             If all the topic files share one global folder there is no need for complicated
822             path expressions in references such as:
823              
824            
825              
826             Extended path names that are repeated across many references are, in effect, a
827             form of boiler plate which can be avoided by applying this standard.
828              
829             =head3 Relocating Dita References After Folder Restructuring
830              
831             In the ideal implementation all files named with the L occupy one
832             global folder. In circumstances where this is not possible, such files can
833             easily be moved into sub folders without fear of collisions, although, any Dita
834             references between such files might have to be updated. This update is easily
835             performed because only the path component has to be updated and the value of
836             the new path can easily be found by searching for the base component of the
837             topic file name using a utility such as L. For a more efficient method,
838             see L.
839              
840             =head3 Similar Files Tend To Appear Close Together In Directory Listings.
841              
842             Imagine the user has several files in different folders all starting:
843              
844             License Agreement
845              
846             The L computes the human readable component of the name in a
847             consistent way using only the contents of each file. Once the name has been
848             standardized, all these files can be placed in B folder to get a directory
849             listing like:
850              
851             license_agreement_a6e3...
852             license_agreement_b532...
853             license_agreement_c65d...
854              
855             This grouping signals that these files are potentially similar to each other
856             and thus might be better merged into one shareable file.
857              
858             As the L is applied to ever more such files, ever more such matches
859             occur.
860              
861             =head3 Copying And Moving Files For Global Interoperability
862              
863             Users can copy files named using the L around from folder to folder
864             without fear of collisions or duplication obviating the need for the time
865             consuming checks and reportage otherwise required before performing such
866             actions. The meta data in the L can also be copied in a similar
867             fearless manner.
868              
869             If two users wish to share content: their files named using the L
870             can be incorporated directly into the other user's file system without fear of
871             collisions or duplicating content thus promoting global content sharing and
872             collaboration of L content.
873              
874             =head3 Guidization For Content Management Systems
875              
876             Self constructed Content Management Systems using BitBucket, GitHub or Gitlab
877             that rely on guidization to differentiate files placed in these repositories
878             benefit immensely: the L to use can be easily derived from the L sum
879             in the L file name.
880              
881             =head3 No need for authors to coordinate topic file names
882              
883             The L is relevant to the administration of a production document
884             corpus. A production corpus being a corpus of documents that is B
885             over time under the control of an administrator.
886              
887             If an author is developing a document from scratch, in splendid isolation,
888             then, initially, the author might well wish to use topic file names of their
889             own choice to contain their topics as this will speed their efforts.
890              
891             For example, it is not uncommon for an author to create a file called:
892              
893             introduction.xml
894              
895             to hold the introduction to the new document they are writing.
896              
897             At some point the system administrator will wish to incorporate the topic files
898             comprising the new document produced by the author into the production corpus.
899              
900             The chance that any of the file names that the author has chosen will conflict
901             with the existing names in the production corpus as generated by the
902             L is negligible. It is thus safe for the administrator to copy the
903             author's topic files directly into the production corpus without renaming any
904             of them. Sooner or later, however, the administrator might wish to run an
905             automated scan of the entire production corpus to rename such recent additions
906             to the L, to update all the references between these files that
907             would otherwise be invalidated by such changes and thereby to clear the
908             production corpus to make it ready to receive other new documents whose topic
909             file names, being chosen by humans, would otherwise very likely conflict with
910             existing topic file names already in the production corpus.
911              
912             Thus clearing the production corpus by applying the L obviates the
913             need for authors to coordinate the names of the files that they choose for
914             their topics with those choosen by other authors allowing each author to
915             proceed efficiently in isolated parallelism, spending more time writing and
916             less time in meetings with other authors discussing their latest file naming
917             strategy.
918              
919             =head3 Using Dita Tags To Describe Content
920              
921             The L encourages L users to use meta data tags to describe
922             their documents so that content can be found by searching with L rather
923             than encoding file meta data in file names then searching for the required file
924             using L. Such file names quickly become very long and unmanageable: on
925             the one hand they need spaces in them to make them readable, but on the other
926             hand, the spaces make such files difficult to cut and paste or use from the
927             L.
928              
929             =head3 Cut And Paste
930              
931             As there are no spaces in the files names created using the L such
932             file names can be selected by a mouse double click and thus easily copied and
933             pasted into other documents.
934              
935             Conversely, one has to use cut and paste to manipulate such file names making
936             it impossible to mistype such file names in other documents.
937              
938             =head3 CSV files
939              
940             Files named using the L can be safely included in B<.csv> files
941             because they have no spaces in them!
942              
943             =head3 Automatic File Versioning
944              
945             Files named to the L File names change when their content changes.
946             So if the content of a file changes its name must change as well. Thus an
947             attempt to present an out-of-date version of a file produces a file name that
948             cannot be found.
949              
950             =head3 Enhanced Command Line Processing
951              
952             As file names named with the L do not have spaces in them (such as
953             L) they work well on the L and with the many
954             L tools that are used to manipulate such files enhancing the
955             productivity leverage that L has always had versus L
956             processing.
957              
958             =head3 Locating Files by Their Original Names Or Other Meta-Data
959              
960             Each file produced by the L can have a L of the same
961             name but without an extension. The L contains meta-data about the
962             file such as its original location etc. which can be searched by L or
963             similar.
964              
965             To find such a file use L to find the L containing the
966             searched for content, paste that file name into the L after
967             entering any command such as B and then press B<.> followed by the L
968             key to have the L expand it to locate the L file that
969             corresponds to the located L. For example:
970              
971             \\grep -r 'SR-dashboard-ds.png'
972              
973             png_f940c7db293fe377e7d49c4e0c654cb2: source => "/home/phil/r/pureStorage/docBook/download/OE_User_Guide/SRRBeta/images/screenshots/dashboard/SR-dashboard-ds.png",
974              
975             ls png_f940c7db293fe377e7d49c4e0c654cb2.png
976              
977             =head3 Use with AWS Simple Storage Service
978              
979             Viewing files held in L is made much easier if they are all in one flat
980             folder with uniqwue base names as there is no folder structure to navigate over
981             a nework. Simply type the start of the B part, the Human Readdable
982             Component, and press enter to see the possible candidates.
983              
984             =head2 Companion File
985              
986             Each file named using the L may be accompanied by a
987             L that contains meta data describing the file, said data
988             formatted as a L data structure.
989              
990             The name of the L is obtained by removing the extension from the
991             file named using the L.
992              
993             As the content of the companion files is in plain text, such text is easy to
994             search using L or other textual search tools.
995              
996             A common use of the companion file is to record the orginal file name and
997             author of the content in question:
998              
999             {source=>q(C:/my documents/dita files/content.dita),
1000             author=>q(A. N. Mouse),
1001             }
1002              
1003             =head2 Alternate File Names
1004              
1005             Most operating systems allow the use of links to supply alternate names for a
1006             file. Consequently, users who wish to impose a different file naming scheme
1007             might care to consider using links to implement their own file naming system on
1008             top of the L without disrupting the integrity of the L.
1009              
1010             For example: L produces B which provide a virtual
1011             hierarchical folder view of an otherwise flat folder.
1012              
1013             =head2 Implementation
1014              
1015             The L has been implemented as a L package at:
1016              
1017             L
1018              
1019             =head2 Binary vs Utf8
1020              
1021             Files that are expected to contain data encoded with L (eg .dita, .xml)
1022             should use method names that start with:
1023              
1024             gbStandard
1025              
1026             Files that are expected to contain binary data (eg .png, .jpg) should use
1027             method names that start with:
1028              
1029             gbBinaryStandard
1030              
1031             The binary standard forms file names by prefixing the L value with the
1032             extension of the file in lower case and an underscore to prevent the long
1033             garbled file names that would otherwise be chosen if the normal standard were
1034             applied directly to naming such content and to group such files close together
1035             in directory listings.
1036              
1037             Consequently, a B file with content:
1038              
1039             q(\0abc\1)
1040              
1041             will be represented by the name:
1042              
1043             png_2786f1147a331ec6ebf60c1ba636a458.png
1044              
1045             =head2 Documentation Copyright
1046              
1047             The documentation for this module is dual licensed with the L as well
1048             as the L in the hope that this will encourage its further dissemination
1049             as a universal standard.
1050              
1051             =head1 Description
1052              
1053             The Gearhart-Brenan Dita Topic Naming Standard.
1054              
1055              
1056             Version 20190901.
1057              
1058              
1059             The following sections describe the methods in each functional area of this
1060             module. For an alphabetic listing of all methods by name see L.
1061              
1062              
1063              
1064             =head1 Make and manage utf8 files
1065              
1066             Make and manage files that conform to the L and are coded in utf8.
1067              
1068             =head2 gbStandardFileName($$%)
1069              
1070             Return the L file name given the content and extension of a proposed file.
1071              
1072             Parameter Description
1073             1 $content Content
1074             2 $extension Extension
1075             3 %options Various ingenious options designed by Micaela
1076              
1077             B
1078              
1079              
1080             if (1) {
1081             if (useWords)
1082             {ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(<
1083            
1084             abc 𝝰𝝱𝝲
1085            
1086            
1087             END
1088             }
1089             else
1090             {ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(<
1091            
1092             abc 𝝰𝝱𝝲
1093            
1094            
1095             END
1096             }
1097             }
1098              
1099              
1100             This method can be imported via:
1101              
1102             use Dita::GB::Standard qw(gbStandardFileName)
1103              
1104              
1105             =head2 gbStandardCompanionFileName($)
1106              
1107             Return the name of the L given a file whose name complies with the L.
1108              
1109             Parameter Description
1110             1 $file L file name
1111              
1112             B
1113              
1114              
1115             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(q(a/b.c)) eq q(a/b);
1116              
1117              
1118             This method can be imported via:
1119              
1120             use Dita::GB::Standard qw(gbStandardCompanionFileName)
1121              
1122              
1123             =head2 gbStandardCompanionFileContent($)
1124              
1125             Return the content of the L given a file whose name complies with the L.
1126              
1127             Parameter Description
1128             1 $file L file name
1129              
1130             B
1131              
1132              
1133             if (1) {
1134             my $s = qq(\0abc\1);
1135             my $S = q(Hello World);
1136             my $d = temporaryFolder;
1137             my $D = temporaryFolder;
1138             clearFolder($_, 10) for $d, $D;
1139              
1140             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1141             ok -e $f;
1142             ok readFile($f) eq $s;
1143              
1144             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1145             ok -e $c;
1146             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($c) eq $S;
1147              
1148             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1149              
1150             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1151             ok -e $F;
1152             ok readFile($F) eq $s;
1153              
1154             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1155             ok -e $C;
1156             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1157              
1158             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($F) eq $S; # Check companion file content
1159              
1160             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1161              
1162             gbBinaryStandardDelete($F); # Delete file and its companion file
1163             ok !-e $F;
1164             ok !-e $C;
1165              
1166             clearFolder($_, 10) for $d, $D;
1167             }
1168              
1169              
1170             This method can be imported via:
1171              
1172             use Dita::GB::Standard qw(gbStandardCompanionFileContent)
1173              
1174              
1175             =head2 gbStandardCreateFile($$$%)
1176              
1177             Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>
1178              
1179             Parameter Description
1180             1 $Folder Target folder or a file in that folder
1181             2 $content Content of the file
1182             3 $extension File extension
1183             4 %options Options.
1184              
1185             B
1186              
1187              
1188             if (1) {
1189             my $s = q(abc 𝝰𝝱𝝲);
1190             my $S = q(Hello World);
1191             my $d = temporaryFolder;
1192             my $D = temporaryFolder;
1193             clearFolder($_, 10) for $d, $D;
1194              
1195             my $f = 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗿𝗲𝗮𝘁𝗲𝗙𝗶𝗹𝗲($d, $s, q(xml), companionContent=>$S); # Create file
1196             ok -e $f;
1197             ok readFile($f) eq $s;
1198              
1199             my $c = gbStandardCompanionFileName($f); # Check companion file
1200             ok -e $c;
1201             ok readFile($c) eq $S;
1202              
1203             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1204             ok -e $F;
1205             ok readFile($F) eq $s;
1206              
1207             my $C = gbStandardCompanionFileName($F); # Check companion file
1208             ok -e $C;
1209             ok readFile($C) eq $S;
1210              
1211             ok !gbStandardRename($F); # No rename required to standardize file name
1212              
1213             gbStandardDelete($F); # Delete file and its companion file
1214             ok !-e $F;
1215             ok !-e $C;
1216              
1217             clearFolder($_, 10) for $d, $D;
1218             }
1219              
1220              
1221             This method can be imported via:
1222              
1223             use Dita::GB::Standard qw(gbStandardCreateFile)
1224              
1225              
1226             =head2 gbStandardRename($%)
1227              
1228             Check whether a file needs to be renamed to match the L. Return the correct name for the file or B if the name is already correct.
1229              
1230             Parameter Description
1231             1 $file File to check
1232             2 %options Options
1233              
1234             B
1235              
1236              
1237             if (1) {
1238             my $s = q(abc 𝝰𝝱𝝲);
1239             my $S = q(Hello World);
1240             my $d = temporaryFolder;
1241             my $D = temporaryFolder;
1242             clearFolder($_, 10) for $d, $D;
1243              
1244             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1245             ok -e $f;
1246             ok readFile($f) eq $s;
1247              
1248             my $c = gbStandardCompanionFileName($f); # Check companion file
1249             ok -e $c;
1250             ok readFile($c) eq $S;
1251              
1252             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1253             ok -e $F;
1254             ok readFile($F) eq $s;
1255              
1256             my $C = gbStandardCompanionFileName($F); # Check companion file
1257             ok -e $C;
1258             ok readFile($C) eq $S;
1259              
1260             ok !𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗥𝗲𝗻𝗮𝗺𝗲($F); # No rename required to standardize file name
1261              
1262             gbStandardDelete($F); # Delete file and its companion file
1263             ok !-e $F;
1264             ok !-e $C;
1265              
1266             clearFolder($_, 10) for $d, $D;
1267             }
1268              
1269              
1270             This method can be imported via:
1271              
1272             use Dita::GB::Standard qw(gbStandardRename)
1273              
1274              
1275             =head2 gbStandardCopyFile($%)
1276              
1277             Copy a file to the specified B<$target> folder renaming it to the L. If no B<$Target> folder is specified then rename the file in its current folder so that it does comply with the L.
1278              
1279             Parameter Description
1280             1 $source Source file
1281             2 %options Options
1282              
1283             B
1284              
1285              
1286             if (1) {
1287             my $s = q(abc 𝝰𝝱𝝲);
1288             my $S = q(Hello World);
1289             my $d = temporaryFolder;
1290             my $D = temporaryFolder;
1291             clearFolder($_, 10) for $d, $D;
1292              
1293             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1294             ok -e $f;
1295             ok readFile($f) eq $s;
1296              
1297             my $c = gbStandardCompanionFileName($f); # Check companion file
1298             ok -e $c;
1299             ok readFile($c) eq $S;
1300              
1301             my $F = 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗽𝘆𝗙𝗶𝗹𝗲($f, target=>$D); # Copy file
1302             ok -e $F;
1303             ok readFile($F) eq $s;
1304              
1305             my $C = gbStandardCompanionFileName($F); # Check companion file
1306             ok -e $C;
1307             ok readFile($C) eq $S;
1308              
1309             ok !gbStandardRename($F); # No rename required to standardize file name
1310              
1311             gbStandardDelete($F); # Delete file and its companion file
1312             ok !-e $F;
1313             ok !-e $C;
1314              
1315             clearFolder($_, 10) for $d, $D;
1316             }
1317              
1318              
1319             This method can be imported via:
1320              
1321             use Dita::GB::Standard qw(gbStandardCopyFile)
1322              
1323              
1324             =head2 gbStandardDelete($)
1325              
1326             Delete a file and its companion file if there is one.
1327              
1328             Parameter Description
1329             1 $file File to delete
1330              
1331             B
1332              
1333              
1334             if (1) {
1335             my $s = q(abc 𝝰𝝱𝝲);
1336             my $S = q(Hello World);
1337             my $d = temporaryFolder;
1338             my $D = temporaryFolder;
1339             clearFolder($_, 10) for $d, $D;
1340              
1341             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1342             ok -e $f;
1343             ok readFile($f) eq $s;
1344              
1345             my $c = gbStandardCompanionFileName($f); # Check companion file
1346             ok -e $c;
1347             ok readFile($c) eq $S;
1348              
1349             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1350             ok -e $F;
1351             ok readFile($F) eq $s;
1352              
1353             my $C = gbStandardCompanionFileName($F); # Check companion file
1354             ok -e $C;
1355             ok readFile($C) eq $S;
1356              
1357             ok !gbStandardRename($F); # No rename required to standardize file name
1358              
1359             𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗗𝗲𝗹𝗲𝘁𝗲($F); # Delete file and its companion file
1360             ok !-e $F;
1361             ok !-e $C;
1362              
1363             clearFolder($_, 10) for $d, $D;
1364             }
1365              
1366              
1367             This method can be imported via:
1368              
1369             use Dita::GB::Standard qw(gbStandardDelete)
1370              
1371              
1372             =head1 Make and manage binary files
1373              
1374             Make and manage files that conform to the L and are in plain binary.
1375              
1376             =head2 gbBinaryStandardFileName($$)
1377              
1378             Return the L file name given the content and extension of a proposed file.
1379              
1380             Parameter Description
1381             1 $content Content
1382             2 $extension Extension
1383              
1384             B
1385              
1386              
1387             if (1) {
1388             if (useWords)
1389             {ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(qq(\0abc\1), q(png)) eq q(png_thInk_BUSHy_dRYER_spaCE_KNOwN_lepeR_SeNse_MaJor.png);
1390             }
1391             else
1392             {ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(qq(\0abc\1), q(png)) eq q(png_2786f1147a331ec6ebf60c1ba636a458.png);
1393             }
1394             }
1395              
1396              
1397             This method can be imported via:
1398              
1399             use Dita::GB::Standard qw(gbBinaryStandardFileName)
1400              
1401              
1402             =head2 gbBinaryStandardCompanionFileName($)
1403              
1404             Return the name of the companion file given a file whose name complies with the L.
1405              
1406             Parameter Description
1407             1 $file L file name
1408              
1409             B
1410              
1411              
1412             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(q(a/b.c)) eq q(a/b);
1413              
1414              
1415             This method can be imported via:
1416              
1417             use Dita::GB::Standard qw(gbBinaryStandardCompanionFileName)
1418              
1419              
1420             =head2 gbBinaryStandardCompanionFileContent($)
1421              
1422             Return the content of the L given a file whose name complies with the binary L.
1423              
1424             Parameter Description
1425             1 $file L file name
1426              
1427             B
1428              
1429              
1430             if (1) {
1431             my $s = qq(\0abc\1);
1432             my $S = q(Hello World);
1433             my $d = temporaryFolder;
1434             my $D = temporaryFolder;
1435             clearFolder($_, 10) for $d, $D;
1436              
1437             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1438             ok -e $f;
1439             ok readFile($f) eq $s;
1440              
1441             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1442             ok -e $c;
1443             ok gbStandardCompanionFileContent($c) eq $S;
1444              
1445             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($f) eq $S; # Check companion file content
1446              
1447             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1448             ok -e $F;
1449             ok readFile($F) eq $s;
1450              
1451             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1452             ok -e $C;
1453             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($C) eq $S;
1454              
1455             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1456              
1457             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1458              
1459             gbBinaryStandardDelete($F); # Delete file and its companion file
1460             ok !-e $F;
1461             ok !-e $C;
1462              
1463             clearFolder($_, 10) for $d, $D;
1464             }
1465              
1466              
1467             This method can be imported via:
1468              
1469             use Dita::GB::Standard qw(gbBinaryStandardCompanionFileContent)
1470              
1471              
1472             =head2 gbBinaryStandardCreateFile($$$$)
1473              
1474             Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>.
1475              
1476             Parameter Description
1477             1 $Folder Target folder or a file in that folder
1478             2 $content Content of the file
1479             3 $extension File extension
1480             4 $companionContent Contents of the companion file.
1481              
1482             B
1483              
1484              
1485             if (1) {
1486             my $s = qq(\0abc\1);
1487             my $S = q(Hello World);
1488             my $d = temporaryFolder;
1489             my $D = temporaryFolder;
1490             clearFolder($_, 10) for $d, $D;
1491              
1492             my $f = 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗿𝗲𝗮𝘁𝗲𝗙𝗶𝗹𝗲($d, $s, q(xml), $S); # Create file
1493             ok -e $f;
1494             ok readFile($f) eq $s;
1495              
1496             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1497             ok -e $c;
1498             ok gbStandardCompanionFileContent($c) eq $S;
1499              
1500             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1501              
1502             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1503             ok -e $F;
1504             ok readFile($F) eq $s;
1505              
1506             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1507             ok -e $C;
1508             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1509              
1510             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1511              
1512             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1513              
1514             gbBinaryStandardDelete($F); # Delete file and its companion file
1515             ok !-e $F;
1516             ok !-e $C;
1517              
1518             clearFolder($_, 10) for $d, $D;
1519             }
1520              
1521              
1522             This method can be imported via:
1523              
1524             use Dita::GB::Standard qw(gbBinaryStandardCreateFile)
1525              
1526              
1527             =head2 gbBinaryStandardRename($)
1528              
1529             Check whether a file needs to be renamed to match the L. Return the correct name for the file or B if the name is already correct.
1530              
1531             Parameter Description
1532             1 $file File to check
1533              
1534             B
1535              
1536              
1537             if (1) {
1538             my $s = qq(\0abc\1);
1539             my $S = q(Hello World);
1540             my $d = temporaryFolder;
1541             my $D = temporaryFolder;
1542             clearFolder($_, 10) for $d, $D;
1543              
1544             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1545             ok -e $f;
1546             ok readFile($f) eq $s;
1547              
1548             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1549             ok -e $c;
1550             ok gbStandardCompanionFileContent($c) eq $S;
1551              
1552             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1553              
1554             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1555             ok -e $F;
1556             ok readFile($F) eq $s;
1557              
1558             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1559             ok -e $C;
1560             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1561              
1562             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1563              
1564             ok !𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗥𝗲𝗻𝗮𝗺𝗲($F); # No rename required to standardize file name
1565              
1566             gbBinaryStandardDelete($F); # Delete file and its companion file
1567             ok !-e $F;
1568             ok !-e $C;
1569              
1570             clearFolder($_, 10) for $d, $D;
1571             }
1572              
1573              
1574             This method can be imported via:
1575              
1576             use Dita::GB::Standard qw(gbBinaryStandardRename)
1577              
1578              
1579             =head2 gbBinaryStandardCopyFile($$)
1580              
1581             Copy a file to the specified B<$target> folder renaming it to the L. If no B<$Target> folder is specified then rename the file in its current folder so that it does comply with the L.
1582              
1583             Parameter Description
1584             1 $source Source file
1585             2 $target Target folder or a file in the target folder
1586              
1587             B
1588              
1589              
1590             if (1) {
1591             my $s = qq(\0abc\1);
1592             my $S = q(Hello World);
1593             my $d = temporaryFolder;
1594             my $D = temporaryFolder;
1595             clearFolder($_, 10) for $d, $D;
1596              
1597             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1598             ok -e $f;
1599             ok readFile($f) eq $s;
1600              
1601             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1602             ok -e $c;
1603             ok gbStandardCompanionFileContent($c) eq $S;
1604              
1605             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1606              
1607             my $F = 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗽𝘆𝗙𝗶𝗹𝗲($f, $D); # Copy file
1608             ok -e $F;
1609             ok readFile($F) eq $s;
1610              
1611             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1612             ok -e $C;
1613             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1614              
1615             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1616              
1617             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1618              
1619             gbBinaryStandardDelete($F); # Delete file and its companion file
1620             ok !-e $F;
1621             ok !-e $C;
1622              
1623             clearFolder($_, 10) for $d, $D;
1624             }
1625              
1626              
1627             This method can be imported via:
1628              
1629             use Dita::GB::Standard qw(gbBinaryStandardCopyFile)
1630              
1631              
1632             =head2 gbBinaryStandardDelete($)
1633              
1634             Delete a file and its L if there is one.
1635              
1636             Parameter Description
1637             1 $file File to delete
1638              
1639             B
1640              
1641              
1642             if (1) {
1643             my $s = qq(\0abc\1);
1644             my $S = q(Hello World);
1645             my $d = temporaryFolder;
1646             my $D = temporaryFolder;
1647             clearFolder($_, 10) for $d, $D;
1648              
1649             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1650             ok -e $f;
1651             ok readFile($f) eq $s;
1652              
1653             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1654             ok -e $c;
1655             ok gbStandardCompanionFileContent($c) eq $S;
1656              
1657             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1658              
1659             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1660             ok -e $F;
1661             ok readFile($F) eq $s;
1662              
1663             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1664             ok -e $C;
1665             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1666              
1667             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1668              
1669             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1670              
1671             𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗗𝗲𝗹𝗲𝘁𝗲($F); # Delete file and its companion file
1672             ok !-e $F;
1673             ok !-e $C;
1674              
1675             clearFolder($_, 10) for $d, $D;
1676             }
1677              
1678              
1679             This method can be imported via:
1680              
1681             use Dita::GB::Standard qw(gbBinaryStandardDelete)
1682              
1683              
1684              
1685             =head1 Index
1686              
1687              
1688             1 L - Return the content of the L given a file whose name complies with the binary L.
1689              
1690             2 L - Return the name of the companion file given a file whose name complies with the L.
1691              
1692             3 L - Copy a file to the specified B<$target> folder renaming it to the L.
1693              
1694             4 L - Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>.
1695              
1696             5 L - Delete a file and its L if there is one.
1697              
1698             6 L - Return the L file name given the content and extension of a proposed file.
1699              
1700             7 L - Check whether a file needs to be renamed to match the L.
1701              
1702             8 L - Return the content of the L given a file whose name complies with the L.
1703              
1704             9 L - Return the name of the L given a file whose name complies with the L.
1705              
1706             10 L - Copy a file to the specified B<$target> folder renaming it to the L.
1707              
1708             11 L - Create a file in the specified B<$Folder> whose name is the L name for the specified B<$content> and return the file name, A L can, optionally, be created with the specified B<$companionContent>
1709              
1710             12 L - Delete a file and its companion file if there is one.
1711              
1712             13 L - Return the L file name given the content and extension of a proposed file.
1713              
1714             14 L - Check whether a file needs to be renamed to match the L.
1715              
1716              
1717              
1718             =head1 Exports
1719              
1720             All of the following methods can be imported via:
1721              
1722             use Dita::GB::Standard qw(:all);
1723              
1724             Or individually via:
1725              
1726             use Dita::GB::Standard qw();
1727              
1728              
1729              
1730             1 L
1731              
1732             2 L
1733              
1734             3 L
1735              
1736             4 L
1737              
1738             5 L
1739              
1740             6 L
1741              
1742             7 L
1743              
1744             8 L
1745              
1746             9 L
1747              
1748             10 L
1749              
1750             11 L
1751              
1752             12 L
1753              
1754             13 L
1755              
1756             14 L
1757              
1758             =head1 Installation
1759              
1760             This module is written in 100% Pure Perl and, thus, it is easy to read,
1761             comprehend, use, modify and install via B:
1762              
1763             sudo cpan install Dita::GB::Standard
1764              
1765             =head1 Author
1766              
1767             L
1768              
1769             L
1770              
1771             =head1 Copyright
1772              
1773             Copyright (c) 2016-2019 Philip R Brenan.
1774              
1775             This module is free software. It may be used, redistributed and/or modified
1776             under the same terms as Perl itself.
1777              
1778             =cut
1779              
1780              
1781              
1782             # Tests and documentation
1783              
1784             sub test
1785 1     1 0 12 {my $p = __PACKAGE__;
1786 1         10 binmode($_, ":utf8") for *STDOUT, *STDERR;
1787 1 50       63 return if eval "eof(${p}::DATA)";
1788 1         54 my $s = eval "join('', <${p}::DATA>)";
1789 1 50       8 $@ and die $@;
1790 1     1   633 eval $s;
  1     1   63649  
  1     1   10  
  1     1   306  
  1         3  
  1         41  
  1         6  
  1         2  
  1         24  
  1         6  
  1         2  
  1         1915  
  1         105  
1791 1 50       1406 $@ and die $@;
1792 1         197 1
1793             }
1794              
1795             test unless caller;
1796              
1797             1;
1798             # podDocumentation
1799             __DATA__