diff --git a/metaprogramming-ruby-talk/.ipynb_checkpoints/Metaprogramming with Ruby-checkpoint.ipynb b/metaprogramming-ruby-talk/.ipynb_checkpoints/Metaprogramming with Ruby-checkpoint.ipynb index f3da4c8..1316624 100644 --- a/metaprogramming-ruby-talk/.ipynb_checkpoints/Metaprogramming with Ruby-checkpoint.ipynb +++ b/metaprogramming-ruby-talk/.ipynb_checkpoints/Metaprogramming with Ruby-checkpoint.ipynb @@ -21,7 +21,18 @@ } }, "source": [ - "" + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "" ] }, { @@ -90,6 +101,17 @@ "Yes, but metaprogramming typically refers to something else in **Ruby**" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "" + ] + }, { "cell_type": "markdown", "metadata": { @@ -112,6 +134,31 @@ "Metaprogramming in ruby refers to code that writes code for you **dynamically. At runtime.**" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "Examples:\n", + "\n", + "* Type Introspection\n", + "* Reflection" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Metaprogramming In Ruby" + ] + }, { "cell_type": "markdown", "metadata": { @@ -160,7 +207,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -202,7 +249,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" @@ -246,9 +293,8 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -330,12 +376,12 @@ } }, "source": [ - "This adds 2 new keywords to the Module class: refine and using." + "This adds 2 new keywords to the Module class: **refine** and **using**." ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" @@ -381,7 +427,7 @@ } }, "source": [ - "![](files/assets/ruby_object_model.png)" + "" ] }, { @@ -478,9 +524,8 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 15, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -563,9 +608,8 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 17, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -586,6 +630,17 @@ "bar" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "**define_method** is defined in the **Module** class, which class **Class** inherits from" + ] + }, { "cell_type": "markdown", "metadata": { @@ -621,9 +676,8 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 20, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -644,11 +698,21 @@ "(1..5).each { |n| send(\"test#{n}\") }" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "**send** is defined in the **Object** class, which all user-defined classes inherits from" + ] + }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 22, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -664,8 +728,6 @@ " end\n", "end\n", "\n", - "# New Code\n", - "\n", "okcpython = OKCPython.new\n", "puts okcpython.send(\"is_boss?\")" ] @@ -680,7 +742,7 @@ "source": [ "The power here comes when you want to call a method based on some in-scope situation - often times based off of a variable value.\n", "\n", - "**Object#send** allows you to call private functions (as you'll see soon). Use **Object#public_send** if you can." + "**Object#send** allows you to call private functions. Use **Object#public_send** if you can." ] }, { @@ -696,9 +758,8 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 27, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -739,9 +800,8 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 29, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -825,9 +885,8 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 32, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -882,9 +941,8 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 38, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -897,13 +955,24 @@ "# the normal way\n", "class Book\n", " def title\n", - " \"All My Friends Are Dead\"\n", + " \"The Handmaid's Tale\"\n", " end\n", "end\n", "\n", "puts Book.new.title" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# 2 Ways to Define a Class" + ] + }, { "cell_type": "markdown", "metadata": { @@ -917,9 +986,8 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 42, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -938,7 +1006,7 @@ " #Both method declaration types work\n", " \n", " define_method('title') do\n", - " \"All My Friends Are Dead\"\n", + " \"The Hobbit\"\n", " end\n", "end\n", "\n", @@ -970,9 +1038,8 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 45, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -985,7 +1052,7 @@ "my_var = \"Success\"\n", "\n", "MyClass = Class.new do\n", - " \"#{my_var} in the class definition\"\n", + " puts \"#{my_var} in the class definition\"\n", " \n", " # Have to use dynamic method creation to access my_var\n", " define_method :my_method do\n", @@ -1026,14 +1093,47 @@ } }, "source": [ - "Most things in Ruby are objects. Blocks are not. To pass them around, you use the **&** operator" + "To get an in-depth explanation:\n", + "https://www.youtube.com/watch?v=_2FjxLVLfhs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Closures: Blocks, Procs, & Lambdas" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "Most things in Ruby are objects. Blocks are not." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "However, there are 2 callable structures that relate to blocks: Procs and Lambdas." ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 47, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1111,22 +1211,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "fragment" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "80\n" - ] - } - ], + "outputs": [], "source": [ + "%%capture\n", "%%ruby\n", "\n", "def lambda_example\n", @@ -1140,9 +1233,8 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 57, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1233,9 +1325,8 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 62, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1277,16 +1368,15 @@ } }, "source": [ - "Even with Open Classes and Dynamic Class creation, we couldn't update a class within another closure (like a method). We also couln't get into a class based on a variable - we had to use the constant.\n", + "Even with Open Classes and Dynamic Class creation, we couldn't update a class within another closure (like a method).\n", "\n", "Until now." ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 68, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1307,6 +1397,52 @@ "puts \"foo\".m" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Class Eval" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "With class_eval, we can also get into a class based on a string variable - instead of the constant." + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "%%capture\n", + "%%ruby\n", + "\n", + "def add_method_to(a_class)\n", + "\n", + " Kernel.const_get(a_class).class_eval do\n", + " def m; 'Hello!'; end\n", + " end\n", + "end\n", + "\n", + "add_method_to(\"String\")\n", + "puts \"foo\".m" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1344,9 +1480,8 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 76, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1375,9 +1510,8 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 78, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1428,9 +1562,8 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 60, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1475,9 +1608,8 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 80, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1529,7 +1661,7 @@ "\n", "https://github.com/alkrauss48\n", "\n", - "https://thesocietea.org" + "https://thecodeboss.dev" ] } ], diff --git a/metaprogramming-ruby-talk/Metaprogramming with Ruby.ipynb b/metaprogramming-ruby-talk/Metaprogramming with Ruby.ipynb index f3da4c8..1316624 100644 --- a/metaprogramming-ruby-talk/Metaprogramming with Ruby.ipynb +++ b/metaprogramming-ruby-talk/Metaprogramming with Ruby.ipynb @@ -21,7 +21,18 @@ } }, "source": [ - "" + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "" ] }, { @@ -90,6 +101,17 @@ "Yes, but metaprogramming typically refers to something else in **Ruby**" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "" + ] + }, { "cell_type": "markdown", "metadata": { @@ -112,6 +134,31 @@ "Metaprogramming in ruby refers to code that writes code for you **dynamically. At runtime.**" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "Examples:\n", + "\n", + "* Type Introspection\n", + "* Reflection" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Metaprogramming In Ruby" + ] + }, { "cell_type": "markdown", "metadata": { @@ -160,7 +207,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" @@ -202,7 +249,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" @@ -246,9 +293,8 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -330,12 +376,12 @@ } }, "source": [ - "This adds 2 new keywords to the Module class: refine and using." + "This adds 2 new keywords to the Module class: **refine** and **using**." ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" @@ -381,7 +427,7 @@ } }, "source": [ - "![](files/assets/ruby_object_model.png)" + "" ] }, { @@ -478,9 +524,8 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 15, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -563,9 +608,8 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 17, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -586,6 +630,17 @@ "bar" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "**define_method** is defined in the **Module** class, which class **Class** inherits from" + ] + }, { "cell_type": "markdown", "metadata": { @@ -621,9 +676,8 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 20, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -644,11 +698,21 @@ "(1..5).each { |n| send(\"test#{n}\") }" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "**send** is defined in the **Object** class, which all user-defined classes inherits from" + ] + }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 22, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -664,8 +728,6 @@ " end\n", "end\n", "\n", - "# New Code\n", - "\n", "okcpython = OKCPython.new\n", "puts okcpython.send(\"is_boss?\")" ] @@ -680,7 +742,7 @@ "source": [ "The power here comes when you want to call a method based on some in-scope situation - often times based off of a variable value.\n", "\n", - "**Object#send** allows you to call private functions (as you'll see soon). Use **Object#public_send** if you can." + "**Object#send** allows you to call private functions. Use **Object#public_send** if you can." ] }, { @@ -696,9 +758,8 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 27, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -739,9 +800,8 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 29, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -825,9 +885,8 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 32, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -882,9 +941,8 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 38, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -897,13 +955,24 @@ "# the normal way\n", "class Book\n", " def title\n", - " \"All My Friends Are Dead\"\n", + " \"The Handmaid's Tale\"\n", " end\n", "end\n", "\n", "puts Book.new.title" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# 2 Ways to Define a Class" + ] + }, { "cell_type": "markdown", "metadata": { @@ -917,9 +986,8 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 42, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -938,7 +1006,7 @@ " #Both method declaration types work\n", " \n", " define_method('title') do\n", - " \"All My Friends Are Dead\"\n", + " \"The Hobbit\"\n", " end\n", "end\n", "\n", @@ -970,9 +1038,8 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 45, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -985,7 +1052,7 @@ "my_var = \"Success\"\n", "\n", "MyClass = Class.new do\n", - " \"#{my_var} in the class definition\"\n", + " puts \"#{my_var} in the class definition\"\n", " \n", " # Have to use dynamic method creation to access my_var\n", " define_method :my_method do\n", @@ -1026,14 +1093,47 @@ } }, "source": [ - "Most things in Ruby are objects. Blocks are not. To pass them around, you use the **&** operator" + "To get an in-depth explanation:\n", + "https://www.youtube.com/watch?v=_2FjxLVLfhs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Closures: Blocks, Procs, & Lambdas" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "Most things in Ruby are objects. Blocks are not." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "However, there are 2 callable structures that relate to blocks: Procs and Lambdas." ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 47, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1111,22 +1211,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "fragment" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "80\n" - ] - } - ], + "outputs": [], "source": [ + "%%capture\n", "%%ruby\n", "\n", "def lambda_example\n", @@ -1140,9 +1233,8 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 57, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1233,9 +1325,8 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 62, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1277,16 +1368,15 @@ } }, "source": [ - "Even with Open Classes and Dynamic Class creation, we couldn't update a class within another closure (like a method). We also couln't get into a class based on a variable - we had to use the constant.\n", + "Even with Open Classes and Dynamic Class creation, we couldn't update a class within another closure (like a method).\n", "\n", "Until now." ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 68, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1307,6 +1397,52 @@ "puts \"foo\".m" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Class Eval" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "With class_eval, we can also get into a class based on a string variable - instead of the constant." + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "%%capture\n", + "%%ruby\n", + "\n", + "def add_method_to(a_class)\n", + "\n", + " Kernel.const_get(a_class).class_eval do\n", + " def m; 'Hello!'; end\n", + " end\n", + "end\n", + "\n", + "add_method_to(\"String\")\n", + "puts \"foo\".m" + ] + }, { "cell_type": "markdown", "metadata": { @@ -1344,9 +1480,8 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 76, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1375,9 +1510,8 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 78, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1428,9 +1562,8 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 60, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1475,9 +1608,8 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 80, "metadata": { - "collapsed": true, "slideshow": { "slide_type": "fragment" } @@ -1529,7 +1661,7 @@ "\n", "https://github.com/alkrauss48\n", "\n", - "https://thesocietea.org" + "https://thecodeboss.dev" ] } ], diff --git a/metaprogramming-ruby-talk/assets/clevyr-fox.png b/metaprogramming-ruby-talk/assets/clevyr-fox.png new file mode 100644 index 0000000..152d282 Binary files /dev/null and b/metaprogramming-ruby-talk/assets/clevyr-fox.png differ diff --git a/metaprogramming-ruby-talk/assets/clevyr.png b/metaprogramming-ruby-talk/assets/clevyr.png index 972466d..58b0fdb 100644 Binary files a/metaprogramming-ruby-talk/assets/clevyr.png and b/metaprogramming-ruby-talk/assets/clevyr.png differ diff --git a/metaprogramming-ruby-talk/assets/wiki.png b/metaprogramming-ruby-talk/assets/wiki.png new file mode 100644 index 0000000..3505489 Binary files /dev/null and b/metaprogramming-ruby-talk/assets/wiki.png differ