diff options
Diffstat (limited to 'sample/trick2025/02-mame')
| -rw-r--r-- | sample/trick2025/02-mame/authors.markdown | 3 | ||||
| -rw-r--r-- | sample/trick2025/02-mame/entry.rb | 34 | ||||
| -rw-r--r-- | sample/trick2025/02-mame/remarks.markdown | 141 | ||||
| -rw-r--r-- | sample/trick2025/02-mame/sample.orig.rb | 8 | ||||
| -rw-r--r-- | sample/trick2025/02-mame/test.patch | 16 |
5 files changed, 202 insertions, 0 deletions
diff --git a/sample/trick2025/02-mame/authors.markdown b/sample/trick2025/02-mame/authors.markdown new file mode 100644 index 0000000000..0e420fdf5d --- /dev/null +++ b/sample/trick2025/02-mame/authors.markdown @@ -0,0 +1,3 @@ +* Yusuke Endoh + * mame@ruby-lang.org + * cctld: jp diff --git a/sample/trick2025/02-mame/entry.rb b/sample/trick2025/02-mame/entry.rb new file mode 100644 index 0000000000..d5de370dc9 --- /dev/null +++ b/sample/trick2025/02-mame/entry.rb @@ -0,0 +1,34 @@ +From:pd <pd-@example.com> (`) +Date:Wed,01 Jan 2025 00:00:00 +0000 +Subject:[PATCH] +an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]} + +--- /dev/null ++++ pd.rb +@@ -0,0 +1,27 @@ ++%;`);;BEGIN{eval$s=%q[eval(%q[F=File;puts((dup)?(q="%;`);;BEGIN ++{eval$s=%q[#$s]}";U,*,V=R=(0..33.0).map{|t|q.gsub(/./){i=$`.siz ++e;c=(i/64*2i-26i+i%64-31)*1i**(t/16.5);x,y=c.rect;r=c.abs;r<13? ++4<=r&&r<6&&x>-4||-5<x&&x<=-3&&-6<y&&y<11??.:?X:$&}};B,A="---|%s ++\n+++|%s\n@@|-%s,%s|+%s,%s|@@\nFrom:pd|<pd-@example.com>|(`)\nD ++ate:%a,%d|%b|%Y|%T|%z\nSubject:[PATCH]|".tr(?|,z="\s")[/@.*\n/] ++,$`;(i=R.index(q))?(S,T=i<33?R[i,(f=->i{(Time.gm(2025)+86400*i) ++.strftime$'};o=f[i+1]+(fXXXXXXXXXXXXXXX[0]+q[/.*\z/]+?\n*2+A%[" ++/dev/null",v="pd.rb"]+XXXXXXXXXXXXXXXXXXXB%[0,0,1,27]+U.gsub(/^ ++/,?+)).lines[-i-2],EXXXXXXXXXXXXXXXXXXXXXXX,a=A%[v,v];V<<"\n(`\ ++n#{a+B%[0,0,1,1]}+dXXXXXXXXXXXXXXXXXXXXXXXXXup=(`)";2)]:($*.siz ++e!=2&&abort(["usagXXXXXXXXX.........XXXXXXXXXe:",$0,F,F]*z);$*. ++map{o=A%$*;F.read(XXXXXXXXX..XXXXXX..XXXXXXXX_1)});a=[i=0]*v=(s ++=[s]+S.lines).sizeXXXXXXXXX..XXXXXX..XXXXXXXX;c=b=s.map{c=_1&&[ ++c,?-+_1,i+=1]||0};XXXXXXXXX..XXXXXX..XXXXXXXXT.lines{|t|s.map{| ++s|a<<((s)?[x=a[-1]XXXXXXXXX.........XXXXXXXXX,y=a[-v]].max+((f= ++s==t)?1:0):0);c,d=(XXXXXXXX..XXXXXXXXXXXXXXXf)?[v+1,z+t]:s&&(x> ++y)?[1,?-+s]:[v,?++t]XXXXXXX..XXXXXXXXXXXXXX;b<<[b[-c],d,i+=1]}} ++;c=b[-1].flatten;b=c[(XXXXX..XXXXXXXXXXXX1..)%2];(b.map{_1[0]}* ++E).scan(/\s{,3}([-+]\s{,XXXXXXXXXXXXXXX6})*[-+]\s{,3}/){n=c[2*i ++=$`.size];o=o,B%[n%v+1-1/v,(m=c[2.*i+j=$&.size]-n)%v,T>""?n/v+1 ++:0,m/v],b[i,j]}):(o=[];a,b=[A,B].map{_1.sub(?+){'\+'}%(['(\S+)' ++]*4)};$<.read=~//;F.write$2,(s=F.readlines$1;o<<[:patching,F,$2 ++]*z;(*,n,i,m=[*$~].map{_1.to_i};n+=m;($'=~/\A((-)|\+)?(.*\n)/;$ ++2?s[i-=1,1]=[]:$1?s[i-1,0]=$3:n-=1;i+=1;n-=1)while+n>0)while/\A ++#{b}/=~$';s*E)while$'=~/^#{a}/);o):([*[?l]*799,1].shuffle*E).sc ++an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]} diff --git a/sample/trick2025/02-mame/remarks.markdown b/sample/trick2025/02-mame/remarks.markdown new file mode 100644 index 0000000000..8be86ebc2d --- /dev/null +++ b/sample/trick2025/02-mame/remarks.markdown @@ -0,0 +1,141 @@ +# A Lesser "Patch" Program + +This program is a minimalistic version of the traditional "patch" command, which looks like a patch. + +## Usage as a "Patch" Command + +The program reads a unified diff file from standard input and applies the changes to the specified files. + +To apply `test.patch` to `sample.rb`, use the following commands: + +``` +$ cp sample.orig.rb sample.rb +$ ruby entry.rb < test.patch +``` + +After running these commands, verify that `sample.rb` has been modified. + +## Usage as a Patch File + +Interestingly, this program is not just a patch-like tools -- it *is* a patch. +This duality allows it to be applied like a regular patch file. + +The following will create a file named pd.rb. + +``` +$ patch < entry.rb +``` + +Alternatively, you can achieve the same result using `entry.rb`: + +``` +$ ruby entry.rb < entry.rb +``` + +The generated `pd.rb` produces a new patch. + +``` +$ ruby pd.rb +``` + +The produced patch is self-referential, targeting `pd.rb` itself. +To apply it: + +``` +$ ruby pd.rb | ruby entry.rb +``` + +You'll notice the `p` logo rotates slightly counterclockwise. + +The modified `pd.rb` outputs the patch for itself again, apply the patch repeatedly--a total of 33 times! + +## From `p` to `d` + +The center `p` logo symbolizes a "patch." +When rotated 180 degrees, it resembles a `d`, signifying a transformation in functionality. +`pd.rb` now operates as a simplified "diff" command: + +``` +$ ruby pd.rb +usage: pd.rb File File + +$ ruby pd.rb sample.orig.rb sample.rb +--- sample.orig.rb ++++ sample.rb +... +``` + +## Integration with Git + +The patches are compatible with Git's `git am` command, which imports patches in mbox format. + +Start fresh by removing `pd.rb` and initializing a Git repository: + +``` +$ rm -f pd.rb +$ git init +Initialized empty Git repository in /home/... +``` + +And import `entry.rb` as a patch to the repository: + +``` +$ git am --committer-date-is-author-date entry.rb +Applying: +(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#_TRICK2025_]} +applying to an empty history +``` + +Verify the commit history: + +``` +$ git log +commit 1e32693f11c1df77bd797c7b3e9f108a3e139824 (HEAD -> main) +Author: pd (`) <pd-@example.com> +Date: Wed Jan 1 00:00:00 2025 +0000 + + +an(/.{40}/));exit].gsub(/X.*X|\n(\h+\s)?\+?/,E=""))#TRICK2025]} +``` + +Notice that the Author and Date are properly set. + +To apply subsequent patches: + +``` +$ for i in `seq 0 32`; do ruby pd.rb | git am --committer-date-is-author-date; done +``` + +*(A fun details: you will see the `b` logo!)* + +Now, view a commit history by the following command: + +``` +$ git log --oneline +``` + +You will rediscover the original `entry.rb` unexpectedly. + +If you set `--committer-date-is-author-date` appropriately, you should be able to run the output of `git log --oneline` as is. + +Try this unusual command: + +``` +$ git log --oneline | ruby - test.patch +``` + +## A Little Something Extra + +Interestingly, `pd.rb` -- functioning as a diff command -- is a patch to itself. +Reveal hidden details with: + +``` +$ ruby entry.rb pd.rb +$ ruby pd.rb +``` + +Can you spot the difference? + +## Limitations + +* I tested it with ruby 3.3.6, git 2.45.2, and GNU patch 2.7.6. +* No error check at all. The lesser patch do not care if there is a discrepancy between what is written in the patch and the input file, and will write over the existing file without prompt. +* It is assumed that the text files have a new line at the end. diff --git a/sample/trick2025/02-mame/sample.orig.rb b/sample/trick2025/02-mame/sample.orig.rb new file mode 100644 index 0000000000..3d880b387d --- /dev/null +++ b/sample/trick2025/02-mame/sample.orig.rb @@ -0,0 +1,8 @@ +def add(a, b) + a + b +end + +if __FILE__ == $0 + result = add(3, 5) + puts "Three plus five is #{ result }" +end diff --git a/sample/trick2025/02-mame/test.patch b/sample/trick2025/02-mame/test.patch new file mode 100644 index 0000000000..0a63ae8a4c --- /dev/null +++ b/sample/trick2025/02-mame/test.patch @@ -0,0 +1,16 @@ +--- sample.rb ++++ sample.rb +@@ -2,7 +2,13 @@ + a + b + end + ++def sub(a, b) ++ a - b ++end ++ + if __FILE__ == $0 + result = add(3, 5) + puts "Three plus five is #{ result }" ++ result = sub(5, 3) ++ puts "five minus three is #{ result }" + end |
