summaryrefslogtreecommitdiff
path: root/sample/trick2025/02-mame
diff options
context:
space:
mode:
Diffstat (limited to 'sample/trick2025/02-mame')
-rw-r--r--sample/trick2025/02-mame/authors.markdown3
-rw-r--r--sample/trick2025/02-mame/entry.rb34
-rw-r--r--sample/trick2025/02-mame/remarks.markdown141
-rw-r--r--sample/trick2025/02-mame/sample.orig.rb8
-rw-r--r--sample/trick2025/02-mame/test.patch16
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