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 -I/home/phil/perl/cpan/DataTableText/lib/
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             # gbBinaryStandardFileName produces different results when given the file name versus the file content - it should be the same
8             package Dita::GB::Standard;
9             our $VERSION = 20201030;
10             require v5.16;
11 1     1   874 use warnings FATAL => qw(all);
  1         7  
  1         38  
12 1     1   6 use strict;
  1         2  
  1         23  
13 1     1   5 use Carp qw(confess);
  1         1  
  1         73  
14 1     1   567 use Data::Dump qw(dump);
  1         7709  
  1         118  
15 1     1   3833 use Data::Table::Text qw(:all);
  1         139524  
  1         1910  
16 1     1   12 use utf8;
  1         2  
  1         22  
17              
18 12     12 0 196 sub useWords{0} #r Use word representation of md5 sum if true
19              
20             # 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.
21             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);
22              
23             !useWords or @words > 2**11 or confess "Not enough words";
24              
25             sub hex4ToBits($) #P Represent 4 hex digits as (1, 1, 1, 1, 1, 12) bits
26 19     19 0 51 {my ($h) = @_;
27 19         39 my $n = hex($h);
28 19         36 my $n11 = $n % 2**11;
29 19         29 my $n12 = ($n>>11) % 2;
30 19         27 my $n13 = ($n>>12) % 2;
31 19         32 my $n14 = ($n>>13) % 2;
32 19         30 my $n15 = ($n>>14) % 2;
33 19         27 my $n16 = ($n>>15) % 2;
34 19         74 ($n16, $n15, $n14, $n13, $n12, $n11);
35             }
36              
37             sub hexAsWords($) #P Given a hex string represent it as words at a rate of 16 bits per word
38 11     11 0 29 {my ($hex) = @_;
39              
40 11         23 my $d = length($hex) % 4;
41 11 50       26 $hex .= '0' x (4-$d) if $d;
42              
43 11         17 my @w;
44              
45 11         35 for my $p(1..length($hex) / 4) # Each block of hex representing 16 bits
46 11         37 {my ($a, $b, $c, $d, $e, $r) = hex4ToBits(substr($hex, 4*($p-1), 4));
47 11         34 my $w = $words[$r];
48 11 100       29 $w = uc(substr($w, 0, 1)).substr($w, 1) if $a;
49 11 100       25 $w = substr($w, 0, 1).uc(substr($w, 1, 1)).substr($w, 2) if $b;
50 11 100       27 $w = substr($w, 0, 2).uc(substr($w, 2, 1)).substr($w, 3) if $c;
51 11 100       28 $w = substr($w, 0, 3).uc(substr($w, 3, 1)).substr($w, 4) if $d;
52 11 100       26 $w = substr($w, 0, 4).uc(substr($w, 4, 1)).substr($w, 5) if $e;
53 11         37 push @w, $w;
54             }
55              
56 11         65 join '_', @w;
57             }
58              
59             #D1 Make and manage utf8 files # Make and manage files that conform to the L and are coded in utf8.
60              
61             sub gbStandardFileName($$%) #E Return the L file name given the content and extension of a proposed file.
62 5     5 1 61 {my ($content, $extension, %options) = @_; # Content, extension, options
63 5 50       35 defined($content) or confess "Content must be defined";
64 5         54 $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.
65              
66 5 50 33     124 $extension && ($extension =~ m(\A\S{2,}\Z)s) or
67             confess "Extension must be non blank and at least two characters long";
68 5   100     67 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.
69 5   33     34241 my $md5 = $options{md5} // stringMd5Sum($content); # Md5 sum either as supplied or computed
70              
71 5 50 66     37565 fpe($name.q(_).(&useWords ? hexAsWords($md5) : $md5), # Add extension
72             fe($extension)||$extension); # fe returns blank given an extension name without a .
73             }
74              
75             sub gbStandardCompanionFileName($) #E Return the name of the L given a file whose name complies with the L.
76 12     12 1 37 {my ($file) = @_; # L file name
77 12         54 setFileExtension($file); # Remove extension to get companion file name
78             }
79              
80             sub gbStandardCompanionFileContent($) #E Return the content of the L given a file whose name complies with the L.
81 2     2 1 10 {my ($file) = @_; # L file name
82 2         15 readFile(gbStandardCompanionFileName($file)) # L companion file name content
83             }
84              
85             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>
86 1     1 1 35 {my ($Folder, $content, $extension, %options) = @_; # Target folder or a file in that folder, content of the file, file extension, options.
87 1         36 my $folder = fp $Folder; # Normalized folder name
88 1         67 my $file = gbStandardFileName($content, $extension, %options); # Entirely satisfactory
89              
90 1         105 my $out = fpf($folder, $file); # Output file
91 1         47 overWriteFile($out, $content); # Write file content
92              
93 1 50       571 if (my $content = $options{companionContent}) # Write a companion file if some content for it has been supplied
94 1         29 {my $comp = gbStandardCompanionFileName($out); # Companion file name
95 1 50       65 if (!-e $comp) # Do not overwrite existing companion file
96 1         20 {writeFile($comp, $content); # Write companion file
97             }
98             else
99 0         0 {lll "Companion file already exists:\n$comp\n";
100             }
101             }
102             $out
103 1         230 }
104              
105             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.
106 2     2 1 8 {my ($file, %options) = @_; # File to check, options
107 2         8 my $content = readFile($file); # Content of proposed file
108 2         360 my $ext = fe($file); # Extension of proposed file
109 2         52 my $proposed = gbStandardFileName($content, $ext, %options); # Proposed name according to the L
110 2         95 my $base = fne($file); # The name of the current file minus the path
111 2 50       45 return undef if $base eq $proposed; # Success - the names match
112 0         0 $proposed # Fail - the name should be this
113             }
114              
115             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.
116 1     1 1 10 {my ($source, %options) = @_; # Source file, options
117 1 50 33     51 -e $source && !-d $source or # Check that the source file exists and is a file
118             confess "Source file to normalize does not exist:\n$source";
119              
120 1         4 my $target = $options{target}; # The target folder (or a file in it) to which to copy this file
121 1         6 my $correctName = gbStandardRename($source, %options); # Get the correct name for the file
122              
123 1 50 33     17 if ($target and $target ne fp($source)) # New target folder specified
    0          
124 1   33     34 {my $t = fpf($target, fne($correctName//$source)); # Target of copy
125 1         55 copyFile($source, $t); # Copy file
126 1         592 my $cs = gbStandardCompanionFileName($source); # Companion file source
127 1         87 my $ct = gbStandardCompanionFileName($t); # Companion file target
128 1 50       25 if (-e $cs) # Copy companion source file if it exists
129 1         6 {copyFile($cs, $ct); # Copy companion source file
130             }
131             else # Create companion target file if it does not exist
132 0         0 {dumpFile($ct, {source=>$source}); # Write source file name to companion file target
133             }
134 1         424 return $t;
135             }
136             elsif ($correctName) # Rename file to match L
137 0         0 {my $t = fpf(fp($source), fne $correctName); # Full file name
138 0         0 rename $source, $t; # Rename file so it matches L
139 0         0 return $t;
140             }
141             undef
142 0         0 }
143              
144             sub gbStandardDelete($) #E Delete a file and its companion file if there is one.
145 1     1 1 26 {my ($file) = @_; # File to delete
146 1         15 my $comp = gbStandardCompanionFileName($file);
147 1         151 unlink $_ for $comp, $file;
148             }
149              
150             #D1 Make and manage binary files # Make and manage files that conform to the L and are in plain binary.
151              
152             sub gbBinaryStandardFileName($$) #E Return the L file name given the content and extension of a proposed file.
153 4     4 1 42 {my ($content, $extension) = @_; # Content a file or a string, extension
154 4 50       35 defined($content) or confess "Content must be defined";
155              
156 4   66     43 my $e = fe($extension) || $extension; # File extension - if given an extension without a leading . fe will return blank
157 4 50       199 $e =~ m(\A\S{2,}\Z)s or
158             confess "Extension must be non blank and at least two characters long: ".
159             dump([$e, $extension]);
160 4         22 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.
161 4         84 my $md5 = stringMd5Sum($content); # Md5 sum
162 4 50       7274 fpe($name.q(_).(&useWords ? hexAsWords($md5) : $md5), $e) # Add extension
163             }
164              
165             sub gbBinaryStandardCompanionFileName($) #E Return the name of the companion file given a file whose name complies with the L.
166 7     7 1 31 {my ($file) = @_; # L file name
167 7         52 setFileExtension($file); # Remove extension to get companion file name
168             }
169              
170             sub gbBinaryStandardCompanionFileContent($) #E Return the content of the L given a file whose name complies with the binary L.
171 2     2 1 9 {my ($file) = @_; # L file name
172 2         13 readFile(gbStandardCompanionFileName($file)) # L companion file name content
173             }
174              
175             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>.
176 1     1 1 30 {my ($Folder, $content, $extension, $companionContent) = @_; # Target folder or a file in that folder, content of the file, file extension, contents of the companion file.
177 1         22 my $folder = fp $Folder; # Normalized folder name
178 1         118 my $file = gbBinaryStandardFileName($content, $extension); # Entirely satisfactory
179              
180 1         78 my $out = fpf($folder, $file); # Output file
181 1         59 overWriteBinaryFile($out, $content); # Write file content
182              
183 1 50       585 if (defined $companionContent) # Write a companion file if some content for it has been supplied
184 1         27 {my $comp = gbBinaryStandardCompanionFileName($out); # Companion file name
185 1 50       71 if (!-e $comp) # Do not overwrite existing companion file
186 1         28 {writeBinaryFile($comp, $companionContent); # Write companion file
187             }
188             else
189 0         0 {lll "Companion file already exists:\n$comp\n";
190             }
191             }
192             $out
193 1         207 }
194              
195             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.
196 2     2 1 7 {my ($file) = @_; # File to check
197 2         14 my $content = readBinaryFile($file); # Content of proposed file
198 2         194 my $proposed = gbBinaryStandardFileName($content, $file); # Proposed name according to the L
199 2         74 my $base = fne($file); # The name of the current file minus the path
200 2 50       56 return undef if $base eq $proposed; # Success - the names match
201 0         0 $proposed # Fail - the name should be this
202             }
203              
204             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.
205 1     1 1 9 {my ($source, $target) = @_; # Source file, target folder or a file in the target folder
206 1 50 33     47 -e $source && !-d $source or # Check that the source file exists and is a file
207             confess "Source file to normalize does not exist:\n$source";
208 1         12 my $correctName = gbBinaryStandardRename($source); # Get the correct name for the file
209 1 50 33     32 if ($target and $target ne fp($source)) # New target folder specified
    0          
210 1   33     42 {my $t = fpf($target, fne($correctName // $source)); # Target of copy
211 1         59 copyBinaryFile($source, $t); # Copy file
212 1         435 my $cs = gbBinaryStandardCompanionFileName($source); # Companion file source
213 1         27 my $ct = gbBinaryStandardCompanionFileName($t); # Companion file target
214              
215 1 50       50 if (-e $cs) # Copy companion source file if it exists
216 1         22 {copyFile($cs, $ct); # Copy companion source file
217             }
218             else # Create companion target file if it does not exist
219 0         0 {dumpFile($ct, {source=>$source}); # Write source file name to companion file target
220             }
221 1         522 return $t;
222             }
223             elsif ($correctName) # Rename file to match L
224 0         0 {my $t = fpf(fp($source), fne $correctName); # Full file name
225 0         0 rename $source, $t; # Rename file so it matches L
226 0         0 return $t;
227             }
228             undef
229 0         0 }
230              
231             sub gbBinaryStandardDelete($) #E Delete a file and its L if there is one.
232 1     1 1 4 {my ($file) = @_; # File to delete
233 1         4 my $comp = gbBinaryStandardCompanionFileName($file);
234 1         146 unlink $_ for $comp, $file;
235             }
236              
237             #Doff
238              
239             say STDERR "gbStandard Exportable Methods:\n",
240             formatTable(reportExportableMethods($0)) if 0;
241              
242             #-------------------------------------------------------------------------------
243             # Export
244             #-------------------------------------------------------------------------------
245              
246 1     1   2920 use Exporter qw(import);
  1         3  
  1         42  
247              
248 1     1   7 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         2  
  1         928  
249              
250             @ISA = qw(Exporter);
251             @EXPORT_OK = qw(
252             gbBinaryStandardCompanionFileContent
253             gbBinaryStandardCompanionFileName
254             gbBinaryStandardCopyFile
255             gbBinaryStandardCreateFile
256             gbBinaryStandardDelete
257             gbBinaryStandardFileName
258             gbBinaryStandardRename
259             gbStandardCompanionFileContent
260             gbStandardCompanionFileName
261             gbStandardCopyFile
262             gbStandardCreateFile
263             gbStandardDelete
264             gbStandardFileName
265             gbStandardRename
266             );
267             %EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
268              
269             # podDocumentation
270              
271             my $nameFromStringMaximumLength = Data::Table::Text::nameFromStringMaximumLength;
272              
273             my $documentationSynopsis = <
274              
275             The L is a means of naming L topic files to enable global
276             collaboration through uncoordinated content sharing.
277              
278             The L creates a human readable, deterministic file name which
279             depends solely on the content to be stored in that file. Such file names are
280             guaranteed to differ between files that contain differing content while being
281             identical for files that contain identical content by the use of an L in
282             the file name.
283              
284             The L name looks like this:
285              
286             human_readable_part_derived_from_content + _ + md5_sum_of_content + extension
287              
288             The human readable part from content is derived solely from the content of the
289             file by interpreting the file content as L encoded as L, then:
290              
291             - replacing instances of xml tags with underscores
292              
293             - replacing all characters other than a-z,A-Z,0-9 with underscores
294              
295             - replacing runs of underscores with a single underscore
296              
297             - removing any leading or trailing underscores
298              
299             - truncating the component if it extends beyond $nameFromStringMaximumLength characters.
300              
301             The original file name for the content is not considered as part of the content
302             of the file and so plays no part in choosing the L name for that
303             content.
304              
305             If the file contains a B tag then only the content of the B<title> tag </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"> is processed as described above to obtain the human readable component of the </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"> file name. If any of the following L<Dita> tags are found in a source file </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"> which also contains a B<title> tag then the following codes are prefixed to </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"> this file name as well: </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">   </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"> Code Tag </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"> bm_ bookmap </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"> c_ concept </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"> r_ reference </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"> t_ task </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">   </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"> The L<md5> component of the file name is calculated from the content of the </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"> file and presented as lowercase hexadecimal. </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">   </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"> The file extension component is obtained from: </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"> L<https://en.wikipedia.org/wiki/List_of_filename_extensions> </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">   </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"> Thus if a B<dita> file has content: </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">   </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"> <concept> </td> </tr> <tr> <td class="h" > <a name="326">326</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <title>abc 𝝰𝝱𝝲
327            
328            
329              
330             then the L name for the file is:
331              
332             c_abc_8551cffdb92932637d952e04447783c8.dita
333              
334             If the option to present the L as five letter English words is chosen
335             then the standardized name for this content becomes:
336              
337             c_abc_Plume_VApoR_CaPER_eqUAl_qUAIL_saInT_mEdia_Irony.dita
338              
339             `head2 Benefits
340              
341             The file names generated by the L can be exploited in numerous ways
342             to simplify the creation, conversion, management and sharing of large
343             repositories of documents written to the L standard:
344              
345             `head3 Parallel Processing
346              
347             Complex long running document transformations can be speeded up by running the
348             transformations in parallel.
349              
350             The file name generated by the L is unique when computed by
351             competing parallel processes so files that have the same name have the same
352             content and can be safely overwritten by another process without attempting to
353             coordinate names between processes. Likewise files that have different names
354             are guarenteed to have different content and so can be written out without
355             checking for an existing file of that name.
356              
357             Alternative systems relying on coordination between the parallel processes to
358             choose names to avoid collisions and reuse identical content perform ever more
359             badly as the number of files increases because there are ever more files to
360             check for matching content and names. Coordination between parallel processes
361             stops the processes from running fully in parallel. Conversely, eliminating the
362             need for coordination between parallel processes allows each process to run
363             more fully in parallel.
364              
365             As a consequence, the L enables parallel L conversions to
366             scale effectively.
367              
368             `head3 File Flattening
369              
370             Files are automatically flattened by the L as files with the same
371             content have the same name and so can safely share one global folder without
372             fear of name collisions or having multiple names for identical content.
373              
374             `head3 Testing
375              
376             The name of each file reflects only its content making it easier to write tests
377             for software build around the L: it is no longer necessary to test
378             that the content of the file is as expected when it is sufficent just to test
379             the base name of the file.
380              
381             One could, of course, compute the L of the file easily during testing
382             but: the fact that one is computing such a sum at all shows just how useful
383             such a sum is, which implies that it should be the one and only piece of meta
384             data encoded in the file name. All othermeta data should reside within the
385             file rather then being encoded in the file name so that said meta data is not
386             destroyed by renaming the file.
387              
388             `head3 Mixed Multiple Conversions
389              
390             When converting documents to L it is a standard practice to perform the
391             conversion in batches by source document type, perhaps B files first, then
392             B files, then L files. Thus leaves the problem of merging the
393             results into one corpus after each individual conversion. The L
394             resolves this problem by guaranteeing the uniqueness of the converted
395             files allowing them to be merged into one results folder without collisions.
396              
397             `head3 No Relative Paths in References
398              
399             If all the topic files share one global folder there is no need for complicated
400             path expressions in references such as:
401              
402            
403              
404             Extended path names that are repeated across many references are, in effect, a
405             form of boiler plate which can be avoided by applying this standard.
406              
407             `head3 Relocating Dita References After Folder Restructuring
408              
409             In the ideal implementation all files named with the L occupy one
410             global folder. In circumstances where this is not possible, such files can
411             easily be moved into sub folders without fear of collisions, although, any Dita
412             references between such files might have to be updated. This update is easily
413             performed because only the path component has to be updated and the value of
414             the new path can easily be found by searching for the base component of the
415             topic file name using a utility such as L. For a more efficient method,
416             see L.
417              
418             `head3 Similar Files Tend To Appear Close Together In Directory Listings.
419              
420             Imagine the user has several files in different folders all starting:
421              
422             License Agreement
423              
424             The L computes the human readable component of the name in a
425             consistent way using only the contents of each file. Once the name has been
426             standardized, all these files can be placed in B folder to get a directory
427             listing like:
428              
429             license_agreement_a6e3...
430             license_agreement_b532...
431             license_agreement_c65d...
432              
433             This grouping signals that these files are potentially similar to each other
434             and thus might be better merged into one shareable file.
435              
436             As the L is applied to ever more such files, ever more such matches
437             occur.
438              
439             `head3 Copying And Moving Files For Global Interoperability
440              
441             Users can copy files named using the L around from folder to folder
442             without fear of collisions or duplication obviating the need for the time
443             consuming checks and reportage otherwise required before performing such
444             actions. The meta data in the L can also be copied in a similar
445             fearless manner.
446              
447             If two users wish to share content: their files named using the L
448             can be incorporated directly into the other user's file system without fear of
449             collisions or duplicating content thus promoting global content sharing and
450             collaboration of L content.
451              
452             `head3 Guidization For Content Management Systems
453              
454             Self constructed Content Management Systems using BitBucket, GitHub or Gitlab
455             that rely on guidization to differentiate files placed in these repositories
456             benefit immensely: the L to use can be easily derived from the L sum
457             in the L file name.
458              
459             `head3 No need for authors to coordinate topic file names
460              
461             The L is relevant to the administration of a production document
462             corpus. A production corpus being a corpus of documents that is B
463             over time under the control of an administrator.
464              
465             If an author is developing a document from scratch, in splendid isolation,
466             then, initially, the author might well wish to use topic file names of their
467             own choice to contain their topics as this will speed their efforts.
468              
469             For example, it is not uncommon for an author to create a file called:
470              
471             introduction.xml
472              
473             to hold the introduction to the new document they are writing.
474              
475             At some point the system administrator will wish to incorporate the topic files
476             comprising the new document produced by the author into the production corpus.
477              
478             The chance that any of the file names that the author has chosen will conflict
479             with the existing names in the production corpus as generated by the
480             L is negligible. It is thus safe for the administrator to copy the
481             author's topic files directly into the production corpus without renaming any
482             of them. Sooner or later, however, the administrator might wish to run an
483             automated scan of the entire production corpus to rename such recent additions
484             to the L, to update all the references between these files that
485             would otherwise be invalidated by such changes and thereby to clear the
486             production corpus to make it ready to receive other new documents whose topic
487             file names, being chosen by humans, would otherwise very likely conflict with
488             existing topic file names already in the production corpus.
489              
490             Thus clearing the production corpus by applying the L obviates the
491             need for authors to coordinate the names of the files that they choose for
492             their topics with those choosen by other authors allowing each author to
493             proceed efficiently in isolated parallelism, spending more time writing and
494             less time in meetings with other authors discussing their latest file naming
495             strategy.
496              
497             `head3 Using Dita Tags To Describe Content
498              
499             The L encourages L users to use meta data tags to describe
500             their documents so that content can be found by searching with L rather
501             than encoding file meta data in file names then searching for the required file
502             using L. Such file names quickly become very long and unmanageable: on
503             the one hand they need spaces in them to make them readable, but on the other
504             hand, the spaces make such files difficult to cut and paste or use from the
505             L.
506              
507             `head3 Cut And Paste
508              
509             As there are no spaces in the files names created using the L such
510             file names can be selected by a mouse double click and thus easily copied and
511             pasted into other documents.
512              
513             Conversely, one has to use cut and paste to manipulate such file names making
514             it impossible to mistype such file names in other documents.
515              
516             `head3 CSV files
517              
518             Files named using the L can be safely included in B<.csv> files
519             because they have no spaces in them!
520              
521             `head3 Automatic File Versioning
522              
523             Files named to the L File names change when their content changes.
524             So if the content of a file changes its name must change as well. Thus an
525             attempt to present an out-of-date version of a file produces a file name that
526             cannot be found.
527              
528             `head3 Enhanced Command Line Processing
529              
530             As file names named with the L do not have spaces in them (such as
531             L) they work well on the L and with the many
532             L tools that are used to manipulate such files enhancing the
533             productivity leverage that L has always had versus L
534             processing.
535              
536             `head3 Locating Files by Their Original Names Or Other Meta-Data
537              
538             Each file produced by the L can have a L of the same
539             name but without an extension. The L contains meta-data about the
540             file such as its original location etc. which can be searched by L or
541             similar.
542              
543             To find such a file use L to find the L containing the
544             searched for content, paste that file name into the L after
545             entering any command such as B and then press B<.> followed by the L
546             key to have the L expand it to locate the L file that
547             corresponds to the located L. For example:
548              
549             \\grep -r 'SR-dashboard-ds.png'
550              
551             png_f940c7db293fe377e7d49c4e0c654cb2: source => "/home/phil/r/pureStorage/docBook/download/OE_User_Guide/SRRBeta/images/screenshots/dashboard/SR-dashboard-ds.png",
552              
553             ls png_f940c7db293fe377e7d49c4e0c654cb2.png
554              
555             `head3 Use with AWS Simple Storage Service
556              
557             Viewing files held in L is made much easier if they are all in one flat
558             folder with uniqwue base names as there is no folder structure to navigate over
559             a nework. Simply type the start of the B part, the Human Readdable
560             Component, and press enter to see the possible candidates.
561              
562             `head2 Companion File
563              
564             Each file named using the L may be accompanied by a
565             L that contains meta data describing the file, said data
566             formatted as a L data structure.
567              
568             The name of the L is obtained by removing the extension from the
569             file named using the L.
570              
571             As the content of the companion files is in plain text, such text is easy to
572             search using L or other textual search tools.
573              
574             A common use of the companion file is to record the orginal file name and
575             author of the content in question:
576              
577             {source=>q(C:/my documents/dita files/content.dita),
578             author=>q(A. N. Mouse),
579             }
580              
581             `head2 Alternate File Names
582              
583             Most operating systems allow the use of links to supply alternate names for a
584             file. Consequently, users who wish to impose a different file naming scheme
585             might care to consider using links to implement their own file naming system on
586             top of the L without disrupting the integrity of the L.
587              
588             For example: L produces B which provide a virtual
589             hierarchical folder view of an otherwise flat folder.
590              
591             `head2 Implementation
592              
593             The L has been implemented as a L package at:
594              
595             L
596              
597             `head2 Binary vs Utf8
598              
599             Files that are expected to contain data encoded with L (eg .dita, .xml)
600             should use method names that start with:
601              
602             gbStandard
603              
604             Files that are expected to contain binary data (eg .png, .jpg) should use
605             method names that start with:
606              
607             gbBinaryStandard
608              
609             The binary standard forms file names by prefixing the L value with the
610             extension of the file in lower case and an underscore to prevent the long
611             garbled file names that would otherwise be chosen if the normal standard were
612             applied directly to naming such content and to group such files close together
613             in directory listings.
614              
615             Consequently, a B file with content:
616              
617             q(\0abc\1)
618              
619             will be represented by the name:
620              
621             png_2786f1147a331ec6ebf60c1ba636a458.png
622              
623             `head2 Documentation Copyright
624              
625             The documentation for this module is dual licensed with the L as well
626             as the L in the hope that this will encourage its further dissemination
627             as a universal standard.
628              
629             END
630              
631             my $removedSections = <
632             `head3 Using Longer Titles To Describe Content
633              
634             The L encourages L writers to choose better titles for their
635             topics. A title of B is fine as far as a single document goes,
636             the subject matter to which we are being introduced is presumably the title of
637             the containing book, perhaps: B.
638              
639             But suppose you are creating a library with millions of searchable books?
640             Problems start to arise: many other books will have introductions too; many of
641             these introductions will share similar sentiments and content. If, like
642             L, you are in the business of selling paper, this is a good thing. If you
643             are management trying to make it easy for readers to find relevant articles
644             while reducing writing costs, then a different approach might be indicated.
645              
646             A first step would be to insist that the proper topic title is more self
647             contained so it can be found in isolation:
648              
649             Introduction to the Art of Making Pasta
650              
651             and that the file that contains this topic starts with a name easily and
652             consistently derived from the title:
653              
654             Introduction_to_the_Art_of_Making_Pasta ....
655              
656             so that it can be more easily found by both readers and writers.
657              
658             A second step might be to standardize introductions as much as possible to
659             reduce their number and to enable the production of targeted variants such as:
660              
661             Introduction to the Art of Making Pasta for Beginners
662              
663             or
664              
665             Introduction to the Art of Making Pasta for Visitors from Italy
666              
667             by mixing and matching standardized content from elsewhere.
668              
669             The L facilitates both of these actions by grouping the
670             introduction files close together further differentiated by an L
671             on the right.
672              
673             An instinctive desire to push the L further to the right where it is less
674             visible encourages the writer to choose a longer more explicit and hopefully
675             unique title.
676              
677             As the file name is derived from the title it is easy for a reader to find a
678             file given the title especially when the title is unique.
679              
680             The fact that the library has millions of topics called B is made
681             abundantly clear to management when the folder holding these files is printed
682             out alphabetically, placed on their desks and they try looking for a topic
683             about B, The difficulties encountered in getting past B encourages
684             management to ask: "Why do we have so many slightly different introductions"?
685              
686             END
687              
688             =pod
689              
690             =encoding utf-8
691              
692             =head1 Name
693              
694             Dita::GB::Standard - The Gearhart-Brenan Dita Topic Naming Standard.
695              
696             =head1 Synopsis
697              
698             The L is a means of naming L topic files to enable global
699             collaboration through uncoordinated content sharing.
700              
701             The L creates a human readable, deterministic file name which
702             depends solely on the content to be stored in that file. Such file names are
703             guaranteed to differ between files that contain differing content while being
704             identical for files that contain identical content by the use of an L in
705             the file name.
706              
707             The L name looks like this:
708              
709             human_readable_part_derived_from_content + _ + md5_sum_of_content + extension
710              
711             The human readable part from content is derived solely from the content of the
712             file by interpreting the file content as L encoded as L, then:
713              
714             - replacing instances of xml tags with underscores
715              
716             - replacing all characters other than a-z,A-Z,0-9 with underscores
717              
718             - replacing runs of underscores with a single underscore
719              
720             - removing any leading or trailing underscores
721              
722             - truncating the component if it extends beyond $nameFromStringMaximumLength characters.
723              
724             The original file name for the content is not considered as part of the content
725             of the file and so plays no part in choosing the L name for that
726             content.
727              
728             If the file contains a B tag then only the content of the B<title> tag </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"> is processed as described above to obtain the human readable component of the </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"> 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="731">731</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="732">732</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="733">733</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="734">734</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="735">735</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="736">736</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="737">737</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="738">738</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="739">739</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="740">740</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="741">741</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="742">742</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="743">743</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="744">744</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="745">745</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="746">746</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="747">747</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="748">748</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="749">749</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> <title>abc 𝝰𝝱𝝲
750            
751            
752              
753             then the L name for the file is:
754              
755             c_abc_8551cffdb92932637d952e04447783c8.dita
756              
757             If the option to present the L as five letter English words is chosen
758             then the standardized name for this content becomes:
759              
760             c_abc_Plume_VApoR_CaPER_eqUAl_qUAIL_saInT_mEdia_Irony.dita
761              
762             =head2 Benefits
763              
764             The file names generated by the L can be exploited in numerous ways
765             to simplify the creation, conversion, management and sharing of large
766             repositories of documents written to the L standard:
767              
768             =head3 Parallel Processing
769              
770             Complex long running document transformations can be speeded up by running the
771             transformations in parallel.
772              
773             The file name generated by the L is unique when computed by
774             competing parallel processes so files that have the same name have the same
775             content and can be safely overwritten by another process without attempting to
776             coordinate names between processes. Likewise files that have different names
777             are guarenteed to have different content and so can be written out without
778             checking for an existing file of that name.
779              
780             Alternative systems relying on coordination between the parallel processes to
781             choose names to avoid collisions and reuse identical content perform ever more
782             badly as the number of files increases because there are ever more files to
783             check for matching content and names. Coordination between parallel processes
784             stops the processes from running fully in parallel. Conversely, eliminating the
785             need for coordination between parallel processes allows each process to run
786             more fully in parallel.
787              
788             As a consequence, the L enables parallel L conversions to
789             scale effectively.
790              
791             =head3 File Flattening
792              
793             Files are automatically flattened by the L as files with the same
794             content have the same name and so can safely share one global folder without
795             fear of name collisions or having multiple names for identical content.
796              
797             =head3 Testing
798              
799             The name of each file reflects only its content making it easier to write tests
800             for software build around the L: it is no longer necessary to test
801             that the content of the file is as expected when it is sufficent just to test
802             the base name of the file.
803              
804             One could, of course, compute the L of the file easily during testing
805             but: the fact that one is computing such a sum at all shows just how useful
806             such a sum is, which implies that it should be the one and only piece of meta
807             data encoded in the file name. All othermeta data should reside within the
808             file rather then being encoded in the file name so that said meta data is not
809             destroyed by renaming the file.
810              
811             =head3 Mixed Multiple Conversions
812              
813             When converting documents to L it is a standard practice to perform the
814             conversion in batches by source document type, perhaps B files first, then
815             B files, then L files. Thus leaves the problem of merging the
816             results into one corpus after each individual conversion. The L
817             resolves this problem by guaranteeing the uniqueness of the converted
818             files allowing them to be merged into one results folder without collisions.
819              
820             =head3 No Relative Paths in References
821              
822             If all the topic files share one global folder there is no need for complicated
823             path expressions in references such as:
824              
825            
826              
827             Extended path names that are repeated across many references are, in effect, a
828             form of boiler plate which can be avoided by applying this standard.
829              
830             =head3 Relocating Dita References After Folder Restructuring
831              
832             In the ideal implementation all files named with the L occupy one
833             global folder. In circumstances where this is not possible, such files can
834             easily be moved into sub folders without fear of collisions, although, any Dita
835             references between such files might have to be updated. This update is easily
836             performed because only the path component has to be updated and the value of
837             the new path can easily be found by searching for the base component of the
838             topic file name using a utility such as L. For a more efficient method,
839             see L.
840              
841             =head3 Similar Files Tend To Appear Close Together In Directory Listings.
842              
843             Imagine the user has several files in different folders all starting:
844              
845             License Agreement
846              
847             The L computes the human readable component of the name in a
848             consistent way using only the contents of each file. Once the name has been
849             standardized, all these files can be placed in B folder to get a directory
850             listing like:
851              
852             license_agreement_a6e3...
853             license_agreement_b532...
854             license_agreement_c65d...
855              
856             This grouping signals that these files are potentially similar to each other
857             and thus might be better merged into one shareable file.
858              
859             As the L is applied to ever more such files, ever more such matches
860             occur.
861              
862             =head3 Copying And Moving Files For Global Interoperability
863              
864             Users can copy files named using the L around from folder to folder
865             without fear of collisions or duplication obviating the need for the time
866             consuming checks and reportage otherwise required before performing such
867             actions. The meta data in the L can also be copied in a similar
868             fearless manner.
869              
870             If two users wish to share content: their files named using the L
871             can be incorporated directly into the other user's file system without fear of
872             collisions or duplicating content thus promoting global content sharing and
873             collaboration of L content.
874              
875             =head3 Guidization For Content Management Systems
876              
877             Self constructed Content Management Systems using BitBucket, GitHub or Gitlab
878             that rely on guidization to differentiate files placed in these repositories
879             benefit immensely: the L to use can be easily derived from the L sum
880             in the L file name.
881              
882             =head3 No need for authors to coordinate topic file names
883              
884             The L is relevant to the administration of a production document
885             corpus. A production corpus being a corpus of documents that is B
886             over time under the control of an administrator.
887              
888             If an author is developing a document from scratch, in splendid isolation,
889             then, initially, the author might well wish to use topic file names of their
890             own choice to contain their topics as this will speed their efforts.
891              
892             For example, it is not uncommon for an author to create a file called:
893              
894             introduction.xml
895              
896             to hold the introduction to the new document they are writing.
897              
898             At some point the system administrator will wish to incorporate the topic files
899             comprising the new document produced by the author into the production corpus.
900              
901             The chance that any of the file names that the author has chosen will conflict
902             with the existing names in the production corpus as generated by the
903             L is negligible. It is thus safe for the administrator to copy the
904             author's topic files directly into the production corpus without renaming any
905             of them. Sooner or later, however, the administrator might wish to run an
906             automated scan of the entire production corpus to rename such recent additions
907             to the L, to update all the references between these files that
908             would otherwise be invalidated by such changes and thereby to clear the
909             production corpus to make it ready to receive other new documents whose topic
910             file names, being chosen by humans, would otherwise very likely conflict with
911             existing topic file names already in the production corpus.
912              
913             Thus clearing the production corpus by applying the L obviates the
914             need for authors to coordinate the names of the files that they choose for
915             their topics with those choosen by other authors allowing each author to
916             proceed efficiently in isolated parallelism, spending more time writing and
917             less time in meetings with other authors discussing their latest file naming
918             strategy.
919              
920             =head3 Using Dita Tags To Describe Content
921              
922             The L encourages L users to use meta data tags to describe
923             their documents so that content can be found by searching with L rather
924             than encoding file meta data in file names then searching for the required file
925             using L. Such file names quickly become very long and unmanageable: on
926             the one hand they need spaces in them to make them readable, but on the other
927             hand, the spaces make such files difficult to cut and paste or use from the
928             L.
929              
930             =head3 Cut And Paste
931              
932             As there are no spaces in the files names created using the L such
933             file names can be selected by a mouse double click and thus easily copied and
934             pasted into other documents.
935              
936             Conversely, one has to use cut and paste to manipulate such file names making
937             it impossible to mistype such file names in other documents.
938              
939             =head3 CSV files
940              
941             Files named using the L can be safely included in B<.csv> files
942             because they have no spaces in them!
943              
944             =head3 Automatic File Versioning
945              
946             Files named to the L File names change when their content changes.
947             So if the content of a file changes its name must change as well. Thus an
948             attempt to present an out-of-date version of a file produces a file name that
949             cannot be found.
950              
951             =head3 Enhanced Command Line Processing
952              
953             As file names named with the L do not have spaces in them (such as
954             L) they work well on the L and with the many
955             L tools that are used to manipulate such files enhancing the
956             productivity leverage that L has always had versus L
957             processing.
958              
959             =head3 Locating Files by Their Original Names Or Other Meta-Data
960              
961             Each file produced by the L can have a L of the same
962             name but without an extension. The L contains meta-data about the
963             file such as its original location etc. which can be searched by L or
964             similar.
965              
966             To find such a file use L to find the L containing the
967             searched for content, paste that file name into the L after
968             entering any command such as B and then press B<.> followed by the L
969             key to have the L expand it to locate the L file that
970             corresponds to the located L. For example:
971              
972             \\grep -r 'SR-dashboard-ds.png'
973              
974             png_f940c7db293fe377e7d49c4e0c654cb2: source => "/home/phil/r/pureStorage/docBook/download/OE_User_Guide/SRRBeta/images/screenshots/dashboard/SR-dashboard-ds.png",
975              
976             ls png_f940c7db293fe377e7d49c4e0c654cb2.png
977              
978             =head3 Use with AWS Simple Storage Service
979              
980             Viewing files held in L is made much easier if they are all in one flat
981             folder with uniqwue base names as there is no folder structure to navigate over
982             a nework. Simply type the start of the B part, the Human Readdable
983             Component, and press enter to see the possible candidates.
984              
985             =head2 Companion File
986              
987             Each file named using the L may be accompanied by a
988             L that contains meta data describing the file, said data
989             formatted as a L data structure.
990              
991             The name of the L is obtained by removing the extension from the
992             file named using the L.
993              
994             As the content of the companion files is in plain text, such text is easy to
995             search using L or other textual search tools.
996              
997             A common use of the companion file is to record the orginal file name and
998             author of the content in question:
999              
1000             {source=>q(C:/my documents/dita files/content.dita),
1001             author=>q(A. N. Mouse),
1002             }
1003              
1004             =head2 Alternate File Names
1005              
1006             Most operating systems allow the use of links to supply alternate names for a
1007             file. Consequently, users who wish to impose a different file naming scheme
1008             might care to consider using links to implement their own file naming system on
1009             top of the L without disrupting the integrity of the L.
1010              
1011             For example: L produces B which provide a virtual
1012             hierarchical folder view of an otherwise flat folder.
1013              
1014             =head2 Implementation
1015              
1016             The L has been implemented as a L package at:
1017              
1018             L
1019              
1020             =head2 Binary vs Utf8
1021              
1022             Files that are expected to contain data encoded with L (eg .dita, .xml)
1023             should use method names that start with:
1024              
1025             gbStandard
1026              
1027             Files that are expected to contain binary data (eg .png, .jpg) should use
1028             method names that start with:
1029              
1030             gbBinaryStandard
1031              
1032             The binary standard forms file names by prefixing the L value with the
1033             extension of the file in lower case and an underscore to prevent the long
1034             garbled file names that would otherwise be chosen if the normal standard were
1035             applied directly to naming such content and to group such files close together
1036             in directory listings.
1037              
1038             Consequently, a B file with content:
1039              
1040             q(\0abc\1)
1041              
1042             will be represented by the name:
1043              
1044             png_2786f1147a331ec6ebf60c1ba636a458.png
1045              
1046             =head2 Documentation Copyright
1047              
1048             The documentation for this module is dual licensed with the L as well
1049             as the L in the hope that this will encourage its further dissemination
1050             as a universal standard.
1051              
1052             =head1 Description
1053              
1054             The Gearhart-Brenan Dita Topic Naming Standard.
1055              
1056              
1057             Version 20190901.
1058              
1059              
1060             The following sections describe the methods in each functional area of this
1061             module. For an alphabetic listing of all methods by name see L.
1062              
1063              
1064              
1065             =head1 Make and manage utf8 files
1066              
1067             Make and manage files that conform to the L and are coded in utf8.
1068              
1069             =head2 gbStandardFileName($$%)
1070              
1071             Return the L file name given the content and extension of a proposed file.
1072              
1073             Parameter Description
1074             1 $content Content
1075             2 $extension Extension
1076             3 %options Various ingenious options designed by Micaela
1077              
1078             B
1079              
1080              
1081             if (1) {
1082             if (useWords)
1083             {ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(<
1084            
1085             abc 𝝰𝝱𝝲
1086            
1087            
1088             END
1089             }
1090             else
1091             {ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(<
1092            
1093             abc 𝝰𝝱𝝲
1094            
1095            
1096             END
1097             }
1098             }
1099              
1100              
1101             This method can be imported via:
1102              
1103             use Dita::GB::Standard qw(gbStandardFileName)
1104              
1105              
1106             =head2 gbStandardCompanionFileName($)
1107              
1108             Return the name of the L given a file whose name complies with the L.
1109              
1110             Parameter Description
1111             1 $file L file name
1112              
1113             B
1114              
1115              
1116             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(q(a/b.c)) eq q(a/b);
1117              
1118              
1119             This method can be imported via:
1120              
1121             use Dita::GB::Standard qw(gbStandardCompanionFileName)
1122              
1123              
1124             =head2 gbStandardCompanionFileContent($)
1125              
1126             Return the content of the L given a file whose name complies with the L.
1127              
1128             Parameter Description
1129             1 $file L file name
1130              
1131             B
1132              
1133              
1134             if (1) {
1135             my $s = qq(\0abc\1);
1136             my $S = q(Hello World);
1137             my $d = temporaryFolder;
1138             my $D = temporaryFolder;
1139             clearFolder($_, 10) for $d, $D;
1140              
1141             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1142             ok -e $f;
1143             ok readFile($f) eq $s;
1144              
1145             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1146             ok -e $c;
1147             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($c) eq $S;
1148              
1149             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1150              
1151             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1152             ok -e $F;
1153             ok readFile($F) eq $s;
1154              
1155             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1156             ok -e $C;
1157             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1158              
1159             ok 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($F) eq $S; # Check companion file content
1160              
1161             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1162              
1163             gbBinaryStandardDelete($F); # Delete file and its companion file
1164             ok !-e $F;
1165             ok !-e $C;
1166              
1167             clearFolder($_, 10) for $d, $D;
1168             }
1169              
1170              
1171             This method can be imported via:
1172              
1173             use Dita::GB::Standard qw(gbStandardCompanionFileContent)
1174              
1175              
1176             =head2 gbStandardCreateFile($$$%)
1177              
1178             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>
1179              
1180             Parameter Description
1181             1 $Folder Target folder or a file in that folder
1182             2 $content Content of the file
1183             3 $extension File extension
1184             4 %options Options.
1185              
1186             B
1187              
1188              
1189             if (1) {
1190             my $s = q(abc 𝝰𝝱𝝲);
1191             my $S = q(Hello World);
1192             my $d = temporaryFolder;
1193             my $D = temporaryFolder;
1194             clearFolder($_, 10) for $d, $D;
1195              
1196             my $f = 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗿𝗲𝗮𝘁𝗲𝗙𝗶𝗹𝗲($d, $s, q(xml), companionContent=>$S); # Create file
1197             ok -e $f;
1198             ok readFile($f) eq $s;
1199              
1200             my $c = gbStandardCompanionFileName($f); # Check companion file
1201             ok -e $c;
1202             ok readFile($c) eq $S;
1203              
1204             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1205             ok -e $F;
1206             ok readFile($F) eq $s;
1207              
1208             my $C = gbStandardCompanionFileName($F); # Check companion file
1209             ok -e $C;
1210             ok readFile($C) eq $S;
1211              
1212             ok !gbStandardRename($F); # No rename required to standardize file name
1213              
1214             gbStandardDelete($F); # Delete file and its companion file
1215             ok !-e $F;
1216             ok !-e $C;
1217              
1218             clearFolder($_, 10) for $d, $D;
1219             }
1220              
1221              
1222             This method can be imported via:
1223              
1224             use Dita::GB::Standard qw(gbStandardCreateFile)
1225              
1226              
1227             =head2 gbStandardRename($%)
1228              
1229             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.
1230              
1231             Parameter Description
1232             1 $file File to check
1233             2 %options Options
1234              
1235             B
1236              
1237              
1238             if (1) {
1239             my $s = q(abc 𝝰𝝱𝝲);
1240             my $S = q(Hello World);
1241             my $d = temporaryFolder;
1242             my $D = temporaryFolder;
1243             clearFolder($_, 10) for $d, $D;
1244              
1245             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1246             ok -e $f;
1247             ok readFile($f) eq $s;
1248              
1249             my $c = gbStandardCompanionFileName($f); # Check companion file
1250             ok -e $c;
1251             ok readFile($c) eq $S;
1252              
1253             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1254             ok -e $F;
1255             ok readFile($F) eq $s;
1256              
1257             my $C = gbStandardCompanionFileName($F); # Check companion file
1258             ok -e $C;
1259             ok readFile($C) eq $S;
1260              
1261             ok !𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗥𝗲𝗻𝗮𝗺𝗲($F); # No rename required to standardize file name
1262              
1263             gbStandardDelete($F); # Delete file and its companion file
1264             ok !-e $F;
1265             ok !-e $C;
1266              
1267             clearFolder($_, 10) for $d, $D;
1268             }
1269              
1270              
1271             This method can be imported via:
1272              
1273             use Dita::GB::Standard qw(gbStandardRename)
1274              
1275              
1276             =head2 gbStandardCopyFile($%)
1277              
1278             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.
1279              
1280             Parameter Description
1281             1 $source Source file
1282             2 %options Options
1283              
1284             B
1285              
1286              
1287             if (1) {
1288             my $s = q(abc 𝝰𝝱𝝲);
1289             my $S = q(Hello World);
1290             my $d = temporaryFolder;
1291             my $D = temporaryFolder;
1292             clearFolder($_, 10) for $d, $D;
1293              
1294             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1295             ok -e $f;
1296             ok readFile($f) eq $s;
1297              
1298             my $c = gbStandardCompanionFileName($f); # Check companion file
1299             ok -e $c;
1300             ok readFile($c) eq $S;
1301              
1302             my $F = 𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗽𝘆𝗙𝗶𝗹𝗲($f, target=>$D); # Copy file
1303             ok -e $F;
1304             ok readFile($F) eq $s;
1305              
1306             my $C = gbStandardCompanionFileName($F); # Check companion file
1307             ok -e $C;
1308             ok readFile($C) eq $S;
1309              
1310             ok !gbStandardRename($F); # No rename required to standardize file name
1311              
1312             gbStandardDelete($F); # Delete file and its companion file
1313             ok !-e $F;
1314             ok !-e $C;
1315              
1316             clearFolder($_, 10) for $d, $D;
1317             }
1318              
1319              
1320             This method can be imported via:
1321              
1322             use Dita::GB::Standard qw(gbStandardCopyFile)
1323              
1324              
1325             =head2 gbStandardDelete($)
1326              
1327             Delete a file and its companion file if there is one.
1328              
1329             Parameter Description
1330             1 $file File to delete
1331              
1332             B
1333              
1334              
1335             if (1) {
1336             my $s = q(abc 𝝰𝝱𝝲);
1337             my $S = q(Hello World);
1338             my $d = temporaryFolder;
1339             my $D = temporaryFolder;
1340             clearFolder($_, 10) for $d, $D;
1341              
1342             my $f = gbStandardCreateFile($d, $s, q(xml), companionContent=>$S); # Create file
1343             ok -e $f;
1344             ok readFile($f) eq $s;
1345              
1346             my $c = gbStandardCompanionFileName($f); # Check companion file
1347             ok -e $c;
1348             ok readFile($c) eq $S;
1349              
1350             my $F = gbStandardCopyFile($f, target=>$D); # Copy file
1351             ok -e $F;
1352             ok readFile($F) eq $s;
1353              
1354             my $C = gbStandardCompanionFileName($F); # Check companion file
1355             ok -e $C;
1356             ok readFile($C) eq $S;
1357              
1358             ok !gbStandardRename($F); # No rename required to standardize file name
1359              
1360             𝗴𝗯𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗗𝗲𝗹𝗲𝘁𝗲($F); # Delete file and its companion file
1361             ok !-e $F;
1362             ok !-e $C;
1363              
1364             clearFolder($_, 10) for $d, $D;
1365             }
1366              
1367              
1368             This method can be imported via:
1369              
1370             use Dita::GB::Standard qw(gbStandardDelete)
1371              
1372              
1373             =head1 Make and manage binary files
1374              
1375             Make and manage files that conform to the L and are in plain binary.
1376              
1377             =head2 gbBinaryStandardFileName($$)
1378              
1379             Return the L file name given the content and extension of a proposed file.
1380              
1381             Parameter Description
1382             1 $content Content
1383             2 $extension Extension
1384              
1385             B
1386              
1387              
1388             if (1) {
1389             if (useWords)
1390             {ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(qq(\0abc\1), q(png)) eq q(png_thInk_BUSHy_dRYER_spaCE_KNOwN_lepeR_SeNse_MaJor.png);
1391             }
1392             else
1393             {ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(qq(\0abc\1), q(png)) eq q(png_2786f1147a331ec6ebf60c1ba636a458.png);
1394             }
1395             }
1396              
1397              
1398             This method can be imported via:
1399              
1400             use Dita::GB::Standard qw(gbBinaryStandardFileName)
1401              
1402              
1403             =head2 gbBinaryStandardCompanionFileName($)
1404              
1405             Return the name of the companion file given a file whose name complies with the L.
1406              
1407             Parameter Description
1408             1 $file L file name
1409              
1410             B
1411              
1412              
1413             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(q(a/b.c)) eq q(a/b);
1414              
1415              
1416             This method can be imported via:
1417              
1418             use Dita::GB::Standard qw(gbBinaryStandardCompanionFileName)
1419              
1420              
1421             =head2 gbBinaryStandardCompanionFileContent($)
1422              
1423             Return the content of the L given a file whose name complies with the binary L.
1424              
1425             Parameter Description
1426             1 $file L file name
1427              
1428             B
1429              
1430              
1431             if (1) {
1432             my $s = qq(\0abc\1);
1433             my $S = q(Hello World);
1434             my $d = temporaryFolder;
1435             my $D = temporaryFolder;
1436             clearFolder($_, 10) for $d, $D;
1437              
1438             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1439             ok -e $f;
1440             ok readFile($f) eq $s;
1441              
1442             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1443             ok -e $c;
1444             ok gbStandardCompanionFileContent($c) eq $S;
1445              
1446             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($f) eq $S; # Check companion file content
1447              
1448             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1449             ok -e $F;
1450             ok readFile($F) eq $s;
1451              
1452             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1453             ok -e $C;
1454             ok 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗙𝗶𝗹𝗲𝗖𝗼𝗻𝘁𝗲𝗻𝘁($C) eq $S;
1455              
1456             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1457              
1458             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1459              
1460             gbBinaryStandardDelete($F); # Delete file and its companion file
1461             ok !-e $F;
1462             ok !-e $C;
1463              
1464             clearFolder($_, 10) for $d, $D;
1465             }
1466              
1467              
1468             This method can be imported via:
1469              
1470             use Dita::GB::Standard qw(gbBinaryStandardCompanionFileContent)
1471              
1472              
1473             =head2 gbBinaryStandardCreateFile($$$$)
1474              
1475             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>.
1476              
1477             Parameter Description
1478             1 $Folder Target folder or a file in that folder
1479             2 $content Content of the file
1480             3 $extension File extension
1481             4 $companionContent Contents of the companion file.
1482              
1483             B
1484              
1485              
1486             if (1) {
1487             my $s = qq(\0abc\1);
1488             my $S = q(Hello World);
1489             my $d = temporaryFolder;
1490             my $D = temporaryFolder;
1491             clearFolder($_, 10) for $d, $D;
1492              
1493             my $f = 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗿𝗲𝗮𝘁𝗲𝗙𝗶𝗹𝗲($d, $s, q(xml), $S); # Create file
1494             ok -e $f;
1495             ok readFile($f) eq $s;
1496              
1497             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1498             ok -e $c;
1499             ok gbStandardCompanionFileContent($c) eq $S;
1500              
1501             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1502              
1503             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1504             ok -e $F;
1505             ok readFile($F) eq $s;
1506              
1507             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1508             ok -e $C;
1509             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1510              
1511             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1512              
1513             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1514              
1515             gbBinaryStandardDelete($F); # Delete file and its companion file
1516             ok !-e $F;
1517             ok !-e $C;
1518              
1519             clearFolder($_, 10) for $d, $D;
1520             }
1521              
1522              
1523             This method can be imported via:
1524              
1525             use Dita::GB::Standard qw(gbBinaryStandardCreateFile)
1526              
1527              
1528             =head2 gbBinaryStandardRename($)
1529              
1530             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.
1531              
1532             Parameter Description
1533             1 $file File to check
1534              
1535             B
1536              
1537              
1538             if (1) {
1539             my $s = qq(\0abc\1);
1540             my $S = q(Hello World);
1541             my $d = temporaryFolder;
1542             my $D = temporaryFolder;
1543             clearFolder($_, 10) for $d, $D;
1544              
1545             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1546             ok -e $f;
1547             ok readFile($f) eq $s;
1548              
1549             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1550             ok -e $c;
1551             ok gbStandardCompanionFileContent($c) eq $S;
1552              
1553             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1554              
1555             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1556             ok -e $F;
1557             ok readFile($F) eq $s;
1558              
1559             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1560             ok -e $C;
1561             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1562              
1563             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1564              
1565             ok !𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗥𝗲𝗻𝗮𝗺𝗲($F); # No rename required to standardize file name
1566              
1567             gbBinaryStandardDelete($F); # Delete file and its companion file
1568             ok !-e $F;
1569             ok !-e $C;
1570              
1571             clearFolder($_, 10) for $d, $D;
1572             }
1573              
1574              
1575             This method can be imported via:
1576              
1577             use Dita::GB::Standard qw(gbBinaryStandardRename)
1578              
1579              
1580             =head2 gbBinaryStandardCopyFile($$)
1581              
1582             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.
1583              
1584             Parameter Description
1585             1 $source Source file
1586             2 $target Target folder or a file in the target folder
1587              
1588             B
1589              
1590              
1591             if (1) {
1592             my $s = qq(\0abc\1);
1593             my $S = q(Hello World);
1594             my $d = temporaryFolder;
1595             my $D = temporaryFolder;
1596             clearFolder($_, 10) for $d, $D;
1597              
1598             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1599             ok -e $f;
1600             ok readFile($f) eq $s;
1601              
1602             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1603             ok -e $c;
1604             ok gbStandardCompanionFileContent($c) eq $S;
1605              
1606             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1607              
1608             my $F = 𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗖𝗼𝗽𝘆𝗙𝗶𝗹𝗲($f, $D); # Copy file
1609             ok -e $F;
1610             ok readFile($F) eq $s;
1611              
1612             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1613             ok -e $C;
1614             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1615              
1616             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1617              
1618             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1619              
1620             gbBinaryStandardDelete($F); # Delete file and its companion file
1621             ok !-e $F;
1622             ok !-e $C;
1623              
1624             clearFolder($_, 10) for $d, $D;
1625             }
1626              
1627              
1628             This method can be imported via:
1629              
1630             use Dita::GB::Standard qw(gbBinaryStandardCopyFile)
1631              
1632              
1633             =head2 gbBinaryStandardDelete($)
1634              
1635             Delete a file and its L if there is one.
1636              
1637             Parameter Description
1638             1 $file File to delete
1639              
1640             B
1641              
1642              
1643             if (1) {
1644             my $s = qq(\0abc\1);
1645             my $S = q(Hello World);
1646             my $d = temporaryFolder;
1647             my $D = temporaryFolder;
1648             clearFolder($_, 10) for $d, $D;
1649              
1650             my $f = gbBinaryStandardCreateFile($d, $s, q(xml), $S); # Create file
1651             ok -e $f;
1652             ok readFile($f) eq $s;
1653              
1654             my $c = gbBinaryStandardCompanionFileName($f); # Check companion file
1655             ok -e $c;
1656             ok gbStandardCompanionFileContent($c) eq $S;
1657              
1658             ok gbBinaryStandardCompanionFileContent($f) eq $S; # Check companion file content
1659              
1660             my $F = gbBinaryStandardCopyFile($f, $D); # Copy file
1661             ok -e $F;
1662             ok readFile($F) eq $s;
1663              
1664             my $C = gbBinaryStandardCompanionFileName($F); # Check companion file
1665             ok -e $C;
1666             ok gbBinaryStandardCompanionFileContent($C) eq $S;
1667              
1668             ok gbStandardCompanionFileContent($F) eq $S; # Check companion file content
1669              
1670             ok !gbBinaryStandardRename($F); # No rename required to standardize file name
1671              
1672             𝗴𝗯𝗕𝗶𝗻𝗮𝗿𝘆𝗦𝘁𝗮𝗻𝗱𝗮𝗿𝗱𝗗𝗲𝗹𝗲𝘁𝗲($F); # Delete file and its companion file
1673             ok !-e $F;
1674             ok !-e $C;
1675              
1676             clearFolder($_, 10) for $d, $D;
1677             }
1678              
1679              
1680             This method can be imported via:
1681              
1682             use Dita::GB::Standard qw(gbBinaryStandardDelete)
1683              
1684              
1685              
1686             =head1 Index
1687              
1688              
1689             1 L - Return the content of the L given a file whose name complies with the binary L.
1690              
1691             2 L - Return the name of the companion file given a file whose name complies with the L.
1692              
1693             3 L - Copy a file to the specified B<$target> folder renaming it to the L.
1694              
1695             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>.
1696              
1697             5 L - Delete a file and its L if there is one.
1698              
1699             6 L - Return the L file name given the content and extension of a proposed file.
1700              
1701             7 L - Check whether a file needs to be renamed to match the L.
1702              
1703             8 L - Return the content of the L given a file whose name complies with the L.
1704              
1705             9 L - Return the name of the L given a file whose name complies with the L.
1706              
1707             10 L - Copy a file to the specified B<$target> folder renaming it to the L.
1708              
1709             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>
1710              
1711             12 L - Delete a file and its companion file if there is one.
1712              
1713             13 L - Return the L file name given the content and extension of a proposed file.
1714              
1715             14 L - Check whether a file needs to be renamed to match the L.
1716              
1717              
1718              
1719             =head1 Exports
1720              
1721             All of the following methods can be imported via:
1722              
1723             use Dita::GB::Standard qw(:all);
1724              
1725             Or individually via:
1726              
1727             use Dita::GB::Standard qw();
1728              
1729              
1730              
1731             1 L
1732              
1733             2 L
1734              
1735             3 L
1736              
1737             4 L
1738              
1739             5 L
1740              
1741             6 L
1742              
1743             7 L
1744              
1745             8 L
1746              
1747             9 L
1748              
1749             10 L
1750              
1751             11 L
1752              
1753             12 L
1754              
1755             13 L
1756              
1757             14 L
1758              
1759             =head1 Installation
1760              
1761             This module is written in 100% Pure Perl and, thus, it is easy to read,
1762             comprehend, use, modify and install via B:
1763              
1764             sudo cpan install Dita::GB::Standard
1765              
1766             =head1 Author
1767              
1768             L
1769              
1770             L
1771              
1772             =head1 Copyright
1773              
1774             Copyright (c) 2016-2019 Philip R Brenan.
1775              
1776             This module is free software. It may be used, redistributed and/or modified
1777             under the same terms as Perl itself.
1778              
1779             =cut
1780              
1781              
1782              
1783             # Tests and documentation
1784              
1785             sub test
1786 1     1 0 12 {my $p = __PACKAGE__;
1787 1         12 binmode($_, ":utf8") for *STDOUT, *STDERR;
1788 1 50       65 return if eval "eof(${p}::DATA)";
1789 1         53 my $s = eval "join('', <${p}::DATA>)";
1790 1 50       8 $@ and die $@;
1791 1     1   746 eval $s;
  1     1   68425  
  1     1   10  
  1     1   312  
  1         2  
  1         43  
  1         6  
  1         3  
  1         23  
  1         6  
  1         4  
  1         2489  
  1         68  
1792 1 50       1659 $@ and die $@;
1793 1         189 1
1794             }
1795              
1796             test unless caller;
1797              
1798             1;
1799             # podDocumentation
1800             __DATA__