diff options
author | Jesse Luehrs <doy@tozt.net> | 2018-10-13 02:17:44 -0400 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2018-10-13 02:37:01 -0400 |
commit | aa403b978860210fcbace7fcdf5830066f3e14e0 (patch) | |
tree | 0d8cf5a8855765ec2d83a865a12814d3b04454e7 | |
parent | ecd7793846441ba90b57140db19474f295f3e6d7 (diff) | |
download | tozt-hugo-aa403b978860210fcbace7fcdf5830066f3e14e0.tar.gz tozt-hugo-aa403b978860210fcbace7fcdf5830066f3e14e0.zip |
import site content
318 files changed, 17187 insertions, 37 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c75eecc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/public diff --git a/archetypes/blog.md b/archetypes/blog.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/blog.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/archetypes/default.md b/archetypes/default.md index 00e77bd..1246302 100644 --- a/archetypes/default.md +++ b/archetypes/default.md @@ -1,6 +1,4 @@ --- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -draft: true +title: "{{ replace .Name "-" " " }}" --- diff --git a/config.toml b/config.toml index e4b7418..087049d 100644 --- a/config.toml +++ b/config.toml @@ -1,3 +1,51 @@ -baseURL = "http://example.org/" +baseURL = "http://new.tozt.net/" languageCode = "en-us" -title = "My New Hugo Site" +title = "Jesse Luehrs" +theme = "tozt" + +newContentEditor = "vim" + +enableGitInfo = true + +[blackfriday] +taskLists = false +smartypants = false +fractions = false +smartDashes = false + +[menu] + +[[menu.main]] +name = "about" +url = "/" +weight = 1 + +[[menu.main]] +name = "work" +url = "/work/" +weight = 2 + +[[menu.main]] +name = "projects" +url = "/projects/" +weight = 3 + +[[menu.main]] +name = "internet" +url = "/internet/" +weight = 4 + +[[menu.main]] +name = "talks" +url = "/talks/" +weight = 5 + +[[menu.main]] +name = "contact" +url = "/contact/" +weight = 6 + +[[menu.main]] +name = "blog" +url = "/blog/" +weight = 7 diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..7a689f0 --- /dev/null +++ b/content/_index.md @@ -0,0 +1,13 @@ +--- +title: "Jesse Luehrs" +--- + +I am a programmer, currently working for [Stripe](https://stripe.com/). + +I was a member of the Fall 1 2014 batch at the [Recurse Center](https://recurse.com/). + +I typically go by "doy" [on the internet](/internet/). + +I graduated from the [University of Illinois at Urbana-Champaign](https://uiuc.edu/) in 2008. + +I'm currently living in New York City. diff --git a/content/blog/hacker-school-day-1.md b/content/blog/hacker-school-day-1.md new file mode 100644 index 0000000..8ffe386 --- /dev/null +++ b/content/blog/hacker-school-day-1.md @@ -0,0 +1,33 @@ +--- +title: hacker school, day 1 +date: "2014-09-02T19:55:00" +tags: [hacker school] +--- + +So I'm finally starting [Hacker School](https://www.hackerschool.com/). Today +was partly an orientation day, and I spent a while meeting people and stuff, +but eventually settled down to work. + +For my first project, I decided to work on an IRC bouncer in +[Rust](http://rust-lang.org/). I've wanted a decent IRC bouncer for a while - +I'm currently using [ZNC](http://wiki.znc.in/ZNC), which is the only really +usable one I've found, but it doesn't really handle disconnection well. I'd +like to be able to just close my laptop and go, and actually get all of the +messages I missed when I open it back up. The problem is that if you don't +explicitly disconnect the IRC client, the bouncer has no way of knowing when +you stopped receiving messages, so messages in that timeout window tend to +just get dropped, which makes it quite difficult to keep up with +conversations. + +The solution I'm going to try is to split the bouncer into two parts, a client +and a server. The server still runs as usual, but you run a bouncer client +locally, and that is what you connect to with your IRC client. The bouncer +client then talks to the bouncer server using a different protocol which +allows you to sync unread messages reliably. + +The first problem that I ran into is that there doesn't appear to be a +fully-featured IRC library for Rust yet (in particular, one that can handle +being a server as well as a client), so... the first step is obviously to +write one! I've done this before [in Lua](https://github.com/doy/luairc), so I +don't think this should be an insurmountable obstacle. We'll see how accurate +that assessment is this week, I suppose. diff --git a/content/blog/keyboard-mappings.md b/content/blog/keyboard-mappings.md new file mode 100644 index 0000000..5109b87 --- /dev/null +++ b/content/blog/keyboard-mappings.md @@ -0,0 +1,141 @@ +--- +title: keyboard mappings +date: "2013-11-02T20:54:00" +tags: [configuration, keyboard] +--- + +So I was at the [Pittsburgh Perl Workshop](http://pghpw.org/ppw2013/), and +[John Anderson](https://twitter.com/genehack) gave a +[talk](http://pghpw.org/ppw2013/talk/5084) about his personal configuration +setup. It motivated me to spend quite a bit of time going over [my own +configuration](https://github.com/doy/conf), but in particular it reminded me +that I had been wanting to adjust my keyboard for a while now. My pinkies have +been getting tired more quickly lately, and I'm fairly sure this is in large +part because of how often I have to use the Shift and Control keys. I do all +of my work on laptops, so it would be pretty inconvenient to get an external +keyboard, so I decided to actually put some effort into looking at ways to +modify my existing keyboard to be easier to type on. + +## Control + +One of the first things I did was read up ways to avoid finger stress. As it +turns out, this is especially common in the Emacs community (since so many of +their keyboard shortcuts rely on weird modifier key combinations), and there's +even a [project](http://ergoemacs.org/) dedicated to making Emacs more +ergonomic. One of the things that they do mention is that contrary to popular +wisdom, [mapping Caps Lock to Control really isn't a very good +solution](http://ergoemacs.org/emacs/swap_CapsLock_Ctrl.html). They recommend +swapping Control and Alt instead, since Control is used far more often, and +you can press the Alt key with your thumb, which is a much stronger finger. + +To do this, I added this to my `.Xmodmap`: + + clear control + clear mod1 + keycode 37 Alt_L Meta_L + keycode 64 Control_L + keycode 105 Alt_R Meta_R + keycode 108 Control_R + add control = Control_L Control_R + add mod1 = Alt_L Alt_R Meta_L Meta_R + +## Shift + +The next thing I started thinking about was how to reduce the usage of the +Shift keys. I do a lot of programming, which uses punctuation characters quite +a bit, and so I started +[wondering](https://twitter.com/doyster/status/388138795557978112) if swapping +the shifted and unshifted number row would be a good idea. As it turns out, +[Brock Wilcox](https://twitter.com/awwaiid) did this [quite a while +ago](http://thelackthereof.org/Keyboard_Number-Symbol_Swap), and he liked it a +lot. Using that as a place to start, I came up with [this +script](https://github.com/doy/conf/blob/master/bin/toggle_numkeys): + + if xmodmap -pk | grep -q '(1).*(exclam).*(1).*(exclam)'; then + xmodmap -e 'keycode 10 = exclam 1' + xmodmap -e 'keycode 11 = at 2' + xmodmap -e 'keycode 12 = numbersign 3' + xmodmap -e 'keycode 13 = dollar 4' + xmodmap -e 'keycode 14 = percent 5' + xmodmap -e 'keycode 15 = asciicircum 6' + xmodmap -e 'keycode 16 = ampersand 7' + xmodmap -e 'keycode 17 = asterisk 8' + xmodmap -e 'keycode 18 = parenleft 9' + xmodmap -e 'keycode 19 = parenright 0' + xmodmap -e 'keycode 20 = underscore minus' + xmodmap -e 'keycode 34 = braceleft bracketleft' + xmodmap -e 'keycode 35 = braceright bracketright' + xmodmap -e 'keycode 49 = asciitilde grave' + xmodmap -e 'keycode 51 = bar backslash' + else + xmodmap -e 'keycode 10 = 1 exclam' + xmodmap -e 'keycode 11 = 2 at' + xmodmap -e 'keycode 12 = 3 numbersign' + xmodmap -e 'keycode 13 = 4 dollar' + xmodmap -e 'keycode 14 = 5 percent' + xmodmap -e 'keycode 15 = 6 asciicircum' + xmodmap -e 'keycode 16 = 7 ampersand' + xmodmap -e 'keycode 17 = 8 asterisk' + xmodmap -e 'keycode 18 = 9 parenleft' + xmodmap -e 'keycode 19 = 0 parenright' + xmodmap -e 'keycode 20 = minus underscore' + xmodmap -e 'keycode 34 = bracketleft braceleft' + xmodmap -e 'keycode 35 = bracketright braceright' + xmodmap -e 'keycode 49 = grave asciitilde' + xmodmap -e 'keycode 51 = backslash bar' + fi + +I bound the script to pressing both Shift keys at once as Brock recommended +(using xbindkeys): + + "toggle_numkeys" + Shift + Shift_R + + "toggle_numkeys" + Shift + Shift_L + +and also set it to run when I logged into X. Note that this also maps a few +other things - besides just the number row, it also makes tilde, underscore, +left and right brace, and pipe into the unshifted characters for their +respective keys. Underscore was the biggest win, I think - typing +`$variable_names_with_lots_of_words_in_them` was always a pretty big strain. + +Again as Brock pointed out, I had to remap the keys in some other applications +to make them stay usable. Strangely enough, both i3 and Firefox continued to +work (I have `Mod4+1`, etc mapped to switching desktops in i3, and Firefox +uses `Alt+1`, etc for tab switching). Not really sure what's going on there. I +did have to add some remappings for the hint mode in +[Pentadactyl](http://5digits.org/pentadactyl/) though: + + set hintkeys=")!@#$%^&*(" + +Zsh, readline, and vim also required remapping `)` to `0`, since I use the `0` +command a lot. Here's from vimrc: + + nmap <silent>) 0 + +and zshrc: + + bindkey -M vicmd ')' vi-digit-or-beginning-of-line + +and inputrc: + + ")": beginning-of-line + +I couldn't figure out how to get the number keys in choose-window mode in tmux +to remap (if anyone has any clues, let me know), but I did rebind the +copy-mode command: + + bind { copy-mode + +So far, I've been using this setup for a little over two weeks, and I'm liking +it a lot. My fingers are noticeably less tired, and I feel like my typing +speed while programming is quite a bit faster. A lot of things feel more +natural too - for instance, `my ($foo_bar, $baz) = @_;` is now typed entirely +without pressing the Shift key, which feels much better. One thing that does +still bother me is that `(:` now requires one shifted and one non-shifted key, +which makes it harder to type, but I'm fairly sure that overall I use `;` more +than `:`, so I don't think switching that is worthwhile. + +In addition to these keyboard remappings, I also remapped a bunch of things in +vim to use fewer keystrokes, but I'll talk about that in a future post. diff --git a/content/blog/writing-an-nes-game-inside-the-cartridge.md b/content/blog/writing-an-nes-game-inside-the-cartridge.md new file mode 100644 index 0000000..14f8891 --- /dev/null +++ b/content/blog/writing-an-nes-game-inside-the-cartridge.md @@ -0,0 +1,12 @@ +--- +title: writing an nes game - inside the cartridge +date: "2014-10-14T12:00:00" +tags: [hacker school, nes] +--- + +As an aside, this is what the inside of an NES cartridge looks like: + +![cartridge image](/blog/cartridge.jpg) + +Note specifically the two physical ROM banks, one labeled PRG and the other +labeled CHR (and basically nothing else on the circuit board). diff --git a/content/blog/writing-an-nes-game-part-1.md b/content/blog/writing-an-nes-game-part-1.md new file mode 100644 index 0000000..b683980 --- /dev/null +++ b/content/blog/writing-an-nes-game-part-1.md @@ -0,0 +1,184 @@ +--- +title: writing an nes game, part 1 +date: "2014-10-13T16:00:00" +tags: [hacker school, nes] +--- + +For the past week or so at Hacker School, I've been learning how to write +games for the NES. This was intended to just be a brief debugging detour for a +different project I was working on, but as these things tend to go, it turned +into an entire project on its own. You can see the end result at +[https://github.com/doy/nes-snake](https://github.com/doy/nes-snake), but I +wanted to go over the code to give an overview about what programming for the +NES is like. + +The NES itself has three processors - a [6502 +CPU](https://en.wikipedia.org/wiki/MOS_Technology_6502), a custom graphics +chip called the PPU (picture processing unit), and a custom sound chip called +the APU (audio processing unit, which I didn't use for this project). Game +data is stored in [ROM](https://en.wikipedia.org/wiki/Read-only_memory) banks, +typically with code and sprite data separate - code is stored in PRG-ROM +(which consists of some number of 16KB banks) and sprite data is stored in +CHR-ROM (which consists of some number of 8KB banks). The only difference +between these two (other than the size) is that PRG-ROM is mapped to the +address space of the CPU and CHR-ROM is mapped to the address space of the PPU +(the different chips also have different address spaces). My game is simple +enough to only require a single PRG-ROM bank and a single CHR-ROM bank. + +The CPU in the NES has a single flat 16-bit address space, which contains +everything from system RAM (there is only 2KB of this), to [memory-mapped IO +ports](https://en.wikipedia.org/wiki/Memory-mapped_I/O) (so reading or writing +at specific memory locations doesn't actually access any memory, it instead +accesses some hardware pins), to battery-backed RAM on the cartridge itself +(if availble), to the actual program ROM. The PPU has its own entirely +separate 14-bit address space, which mostly holds raw sprite data, color +palettes, and information about which sprites should be drawn in which +locations on the screen (that last part is typically the only thing that needs +to be touched in a simple game). + +So this is what the basic skeleton of a small NES program (which uses a +single 16KB PRG-ROM bank and a single 8KB CHR-ROM bank) looks like: + +```asm +; .ROMBANKMAP describes the layout of the ROM banks that this assembly file +; will produce. They will end up laid out sequentially in the output file. In +; this case, we're writing a game that requires one 16KB PRG-ROM bank and one +; 8KB CHR-ROM bank, so we specify that there are two banks in total, and we +; then specify the sizes for each of those two banks. The output file, once +; linked, will be a 24KB file, where the first 16KB is the PRG-ROM data and +; the last 8KB is the CHR-ROM data. +.ROMBANKMAP +BANKSTOTAL 2 +BANKSIZE $4000 ; PRG-ROM is 16KB +BANKS 1 +BANKSIZE $2000 ; CHR-ROM is 8KB +BANKS 1 +.ENDRO + +; .MEMORYMAP describes how the ROM banks will be loaded into memory. On the +; NES, program ROM has $8000-$FFFF available to it in the address space (which +; corresponds to two banks of PRG-ROM data), but if you're only using a single +; bank, it is typically loaded at $C000 (since the interrupt vectors must be +; located at $FFFA/$FFFC/$FFFE). The CHR-ROM data isn't mapped into the main +; address space (it is instead mapped into the PPU's address space), so it +; doesn't actually matter what address we tell it to load into. +.MEMORYMAP +DEFAULTSLOT 0 +SLOTSIZE $4000 +SLOT 0 $C000 ; a single PRG-ROM bank should be mapped at $C000 +SLOTSIZE $2000 +SLOT 1 $0000 ; this location doesn't matter, CHR-ROM isn't in main memory +.ENDME + +; .ENUM just creates a mapping of names to values. Variables don't actually +; exist in assembly - all you have is memory locations, and so variables +; can be simulated by creating aliases to locations in memory. +; .ENUM is just a convenient shortcut for defining labels that point +; to data. On the NES, the internal system RAM is located at $0000-$0800 (2KB), +; and so we can just define labels that point into that section of memory and +; use them as variables. In addition, most 6502 opcodes are shorter and faster +; if they are accessing memory within $0000-$00FF (called the "zero page"), and +; so we should try to put most common variables within that portion of memory. +; In addition to putting variables in the zero page, NES programs typically use +; $0100-$01FF for the stack (used by the PHA/PLA instructions) and $0200-$02FF +; for holding sprite data until it can be copied to the PPU, so you should +; avoid using those sections of RAM for arbitrary game data. +.ENUM $00 +; global variable declarations go here +.ENDE + +; This defines the first ROM bank (bank 0), and indicates that it will be +; loaded into slot 0 as defined above. + .bank 0 slot 0 +; .org indicates the offset that the following assembly code will be created +; at, relative to the start of the current ROM bank. In this case, we're using +; an offset of $0000, so this code will be loaded into the NES address space +; starting at $C000. + .org $0000 + +; The RESET label is the code that will be jumped to at power on (see below) +RESET: + ; TODO: initialization code goes here +loop: + ; TODO: game code goes here + JMP loop + +; The NMI label is the code that will be jumped to at the start of each frame +; (see below) +NMI: + ; TODO: per-frame drawing code goes here + RTI + +; .orga defines the absolute address that the following assembly code will be +; created at. It must be a value within the current ROM bank. We're using .orga +; here because $FFFA is a special value to the NES, and so using it literally +; makes the code easier to understand. $FFFA is the start of three interrupt +; vectors that define which code to run when various things happen. The first +; one is the NMI handler, which runs on each frame. The second is the RESET +; handler, which runs at system startup. The third is the IRQ handler, which +; runs on external interrupts (usually from the APU or various external chips). +; We don't use the IRQ handler because we aren't doing any sound, and we aren't +; using any external chips, so it is just set to 0 (which disables it). + .orga $FFFA + .dw NMI ; $FFFA contains the address to jump to at the start of each frame + .dw RESET ; $FFFC contains the address to jump to at power-on + .dw 0 ; $FFFE contains the address to jump to on an external interrupt + +; This defines the second bank, which holds the CHR-ROM. + .bank 1 slot 1 + .org $0000 +; .incbin includes the contents of an external file literally into the output. +; Here, sprites.chr should contain the literal contents of the CHR-ROM. This is +; easier because the CHR-ROM doesn't contain any code, so defining it inline in +; the assembly code file would be quite a bit less convenient. I'll talk about +; ways to actually edit this file later. + .incbin "sprites.chr" ; sprites.chr should be 8192 bytes +``` + +This is using the syntax for the WLA DX assembler, which works well on Linux +(most of the existing tutorials I've seen use various Windows-only +assemblers). I'm using the +[`wla_dx`](https://aur.archlinux.org/packages/wla_dx/) AUR package on Arch +Linux, but similar packages should be available for most distros. To compile +this code, follow these steps: + +* Save the code as `test.s` +* Run `dd if=/dev/zero of=sprites.chr bs=8192 count=1` to create an empty CHR + data file (which will be included in the output) +* Run `wla-6502 -o test.s` to generate an object file called `test.o` +* Create a file named `linkfile` which is used by the linker, with the contents + +``` +[objects] +test.o +``` + +* Run `wlalink linkfile test.rom` to create the actual ROM + +This ROM is not yet in the format required to be run by most NES emulators. To +get it into this format, we need to add a 16-byte header which describes the +layout of the file. You can download the header I used from +[here](https://raw.githubusercontent.com/doy/nes-snake/master/header.bin) - it +specifies a layout containing one PRG-ROM bank and one CHR-ROM bank. If you're +interested in doing something different, you should read up on the [iNES ROM +format](http://wiki.nesdev.com/w/index.php/INES). + +Once you have a file containing the header, you can create a file that will +actually work in an NES emulator by running `cat header.bin test.rom > +test.nes`. To run the ROM, I highly recommend using an emulator that aims for +accuracy - a lot of emulators out there aim for compatibility, which typically +means hacks for specific known games, and which will quite possibly just +result in breaking games that they don't know about (including new games you +are writing). Nestopia is a good recommendation if you don't know much about +the subject. To execute the ROM you just created, run `nestopia test.nes`. You +should just see a blank screen, since we haven't included any code to make it +do anything differently, but it should successfully load and run. + +Next time I'll talk about the structure of the actual code in an NES game. For +further information about the topics in this post, here are some useful links: + +* [WLA DX assembler reference](http://www.villehelin.com/wla.txt) +* [NES Assembly Tutorial](http://nixw0rm.altervista.org/files/nesasm.pdf) +* [NES Architecture](http://fms.komkon.org/EMUL8/NES.html) +* [NES 101](http://hackipedia.org/Platform/Nintendo/NES/tutorial%2c%20NES%20programming%20101/NES101.html) +* [NES technical documentation](http://emu-docs.org/NES/nestech.txt) diff --git a/content/blog/writing-an-nes-game-part-2.md b/content/blog/writing-an-nes-game-part-2.md new file mode 100644 index 0000000..d2cd675 --- /dev/null +++ b/content/blog/writing-an-nes-game-part-2.md @@ -0,0 +1,257 @@ +--- +title: writing an nes game, part 2 +date: "2014-10-14T15:30:00" +tags: [hacker school, nes] +--- + +# code layout + +So before we get into the code itself, there are a couple more concepts that +will be important to understand, in order to understand why the code is laid +out the way it is. + +First, we need to understand how the PPU handles drawing. The NES was designed +to work on CRT screens, which work by drawing a horizontal line at a time from +the top of the screen to the bottom, at which point it starts again at the +top. This is done by a device called an [electron +gun](https://en.wikipedia.org/wiki/Electron_gun), which fires electrons at a +screen of pixels. The key point here is that drawing is done sequentially, one +pixel at a time, and the mechanism requires some amount of time to move from +one line to the next, and to move from the bottom of the screen back to the +top. The period of time when the electron gun is moving from the end of one +line to the beginning of the next is called the "HBlank" time, and the period +of time when the electron gun is moving from the bottom of the screen back to +the top is called the "VBlank" time. Except during HBlank and VBlank, the PPU +is busy controlling what actually needs to be drawn, and manipulating it at +all can cause all kinds of weird graphical glitches, so we need to make sure +we only communicate with the PPU during HBlank or VBlank. + +The way the NES handles this is to provide an interrupt (called NMI) which +fires at the beginning of every VBlank, which allows you to do all of your +drawing during a safe period of time. HBlank is harder to detect and not as +useful (since it occurs in the middle of drawing a frame), and so it is not +typically used except for some visual effects. NTSC television screens refresh +at 60 frames per second, and the CPU clock speed in the NES is approximately +1.79MHz, and so we get approximately 30,000 CPU cycles per frame, which +translates into roughly 5,000-10,000 opcodes. VBlank, though, only lasts +around 2273 cycles (roughly 400-800 opcodes), so drawing code needs to be +especially efficient. In particular, we don't want to do any game logic at all +during VBlank time, since that time is so limited. + +The other aspect that needs to be handled is system initialization. When the +CPU starts up, it's in an undefined state, so we need to set things up to +ensure that the game executes in a repeatable way. Emulators tend to be +consistent in how they initialize the system state at startup, but this isn't +true of the real hardware, so it's important to do this explicitly. Also, the +PPU requires initialization, but that is handled automatically. It does take a +bit over 30,000 CPU cycles though (a little over one frame), so we wait for +two frames before starting our main game code. Two frames is plenty of time to +do any initialization we might need to do. + +To illustrate these concepts, here is an example program which modifies the +background color every second. The details about how the background color is +set isn't particularly important (it's not really a feature you're likely to +use very often), but this should illustrate the basic structure of an NES +game. This isn't intended to be a lesson on 6502 assembly (there are plenty of +much better tutorials and references out there for that - see below), but just +to show how games for the NES specifically are structured. + +```asm +.ROMBANKMAP +BANKSTOTAL 2 +BANKSIZE $4000 +BANKS 1 +BANKSIZE $2000 +BANKS 1 +.ENDRO + +.MEMORYMAP +DEFAULTSLOT 0 +SLOTSIZE $4000 +SLOT 0 $C000 +SLOTSIZE $2000 +SLOT 1 $0000 +.ENDME + +.ENUM $00 +; declare the label 'sleeping' to refer to the byte at memory location $0000 +sleeping DB +; 'color' will then be at $0001 +color DB +; and 'frame_count' will be at $0002 +frame_count DB +.ENDE + + .bank 0 slot 0 + .org $0000 +RESET: + ; First, we disable pretty much everything while we try to get the system + ; into a consistent state. In particular, we really don't want any + ; interrupts to fire until the stack pointer is set up (because interrupt + ; calls use the stack), and we don't want any drawing to be done until the + ; PPU is initialized. + SEI ; disable all IRQs + CLD ; disable decimal mode + LDX #$FF + TXS ; Set up stack (grows down from $FF to $00, at $0100-$01FF) + INX ; now X = 0 + STX $2000.w ; disable NMI (we'll enable it later once the ppu is ready) + STX $2001.w ; disable rendering (we're not using it in this example) + STX $4010.w ; disable DMC IRQs + LDX #$40 + STX $4017.w ; disable APU frame IRQ + + ; First wait for vblank to make sure PPU is ready. The processor sets a + ; status bit when vblank ends, so we just loop until we notice it. +vblankwait1: + BIT $2002 ; bit 7 of $2002 is reset once vblank ends + BPL vblankwait1 ; and bit 7 is what is checked by BPL + + ; set everything in ram ($0000-$07FF) to $00, except for $0200-$02FF which + ; is conventionally used to hold sprite attribute data. we set that range + ; to $FE, since that value as a position moves the sprites offscreen, and + ; when the sprites are offscreen, it doesn't matter which sprites are + ; selected or what their attributes are +clrmem: + LDA #$00 + STA $0000, x + STA $0100, x + STA $0300, x + STA $0400, x + STA $0500, x + STA $0600, x + STA $0700, x + LDA #$FE + STA $0200, x + INX + BNE clrmem + + ; initialize variables in ram + LDA #%10000001 + STA color + ; no need to initialize frame_count or sleeping, since we just set them to + ; $00 in the clrmem loop + + ; Second wait for vblank, PPU is ready after this +vblankwait2: + BIT $2002 + BPL vblankwait2 + + LDA #%10000000 ; enable NMI interrupts now that the PPU is ready + STA $2000 + +loop: + ; sleep while vblank is happening. this serializes the code flow a bit + ; (the NMI interrupt will almost certainly occur while we are in this loop + ; unless we do a significant amount of processing in the main codepath, so + ; it won't interrupt anything important). it also ensures that our game + ; logic only executes once per frame. + INC sleeping +wait_for_vblank_end: + LDA sleeping + BNE wait_for_vblank_end + + ; change color every 60 frames + LDX frame_count + CPX #60 + BCS change_color + INX + STX frame_count + JMP loop_end + +change_color: + LDA #$00 + STA frame_count + LDX color + CPX #%10000001 + BEQ turn_green + CPX #%01000001 + BEQ turn_red + +turn_blue: + LDA #%10000001 + STA color + JMP loop_end +turn_green: + LDA #%01000001 + STA color + JMP loop_end +turn_red: + LDA #%00100001 + STA color + +loop_end: + JMP loop + +NMI: + ; save the contents of the registers on the stack, since the interrupt can + ; be called at any point in our main loop + PHA + TXA + PHA + TYA + PHA + + LDA color + STA $2001 + + ; indicate that we're done drawing for this frame + LDA #$00 + STA sleeping + ; and restore the register contents before returning + PLA + TAY + PLA + TAX + PLA + + RTI + + .orga $FFFA + .dw NMI + .dw RESET + .dw 0 + + .bank 1 slot 1 + .org $0000 + .incbin "sprites.chr" +``` + +The first thing we do when the system turns on is disable IRQ interrupts. +Calling and returning from interrupts uses the system stack, but the stack +pointer could be pointing anywhere at this point, and so interrupts would be +confuse things quite a bit. We never reenable IRQ interrupts here because we +don't use them at all (they would be reenabled by the `CLI` instruction). Next +we disable decimal mode (this shouldn't actually do anything, since the NES +doesn't have a BCD chip, but no real reason not to do this, to avoid +confusion) and set the stack pointer to `$FF`. The stack pointer is stored in +the register named S, and it is a one-byte offset from the RAM address +`$0100`. The stack grows downward, so the stack pointer should start out +pointing to `$01FF`, and then it will be decremented by `PHA` instructions and +incremented by `PLA` instructions as necessary. Finally, we disable a bunch of +other functionality on the PPU and APU, since we don't want them to be active +until we have finished initializing. + +We need to wait for a total of two frames to ensure that the PPU is entirely +initialized, so we next wait for the first frame to end, and then clear out +the entire RAM space, and then wait for the second frame to end. At this +point, the PPU is initialized, so we can enable NMI interrupts (by setting a +bit in the PPU control register at `$2000`) and begin our main loop. + +The main loop is where all of the logic goes. In this example, we just +increment the frame count every frame, and change the background color (via +some magic) every 60 frames. This allows the NMI interrupt to do nothing more +than write a single value to the PPU, without requiring any logic at all. This +illustrates the basic principle of using the main game loop to set up values +in memory, which the code in the NMI interrupt can just read and act on +directly, without requiring any calculations. + +Here are some more useful links discussing the topics in this post: + +* [NES ASM Tutorial](http://nixw0rm.altervista.org/files/nesasm.pdf) +* [The frame and NMIs](http://wiki.nesdev.com/w/index.php/The_frame_and_NMIs) +* [6502 instruction set + overview](http://www.dwheeler.com/6502/oneelkruns/asm1step.html) +* [6502 instruction set + reference](http://e-tradition.net/bytes/6502/6502_instruction_set.html) +* [NES technical documentation](http://emu-docs.org/NES/nestech.txt) diff --git a/content/blog/writing-an-nes-game-part-3.md b/content/blog/writing-an-nes-game-part-3.md new file mode 100644 index 0000000..749b76d --- /dev/null +++ b/content/blog/writing-an-nes-game-part-3.md @@ -0,0 +1,95 @@ +--- +title: writing an nes game, part 3 +date: "2014-10-15T15:30:00" +tags: [hacker school, nes] +--- + +# input handling + +Now that we have a general idea of how a program for the NES is structured, +it'd be useful to get a bit further into the specific capabilities of the NES. +One of the pretty basic (and pretty important) ones is reading input from the +controllers. + +The basic structure of an NES controller is a [shift +register](https://en.wikipedia.org/wiki/Shift_register). To read the +controller inputs, you send a signal to the latch pin, which stores the state +of the input buttons in the register, and then you send a sequence of signals +to the clock pin to put the state of each button on the output in sequentially +(A, B, Select, Start, Up, Down, Left, Right). As it turns out, the code you +have to write to read from the controller maps pretty exactly to these +operations. This is what it looks like: + +```asm +read_controller1: + ; memory address $4016 corresponds to the shift register inside the + ; controller plugged into the first controller port. writing to it sets the + ; state of the latch pin, and so we set the latch pin high and then low in + ; order to store the controller state in the shift register. + LDA #$01 + STA $4016 + LDA #$00 + STA $4016 + + ; reading from $4016 reads the output value of the data pin and also sends a + ; signal to the clock pin in order to put the next bit of data on the output + ; for the next read. the value that is read has the state of the button in + ; the low bit, and the upper bits contain various other pieces of + ; information (such as whether a controller is plugged in at all, etc), so + ; if we only care about the state of the button we have to mask out + ; everything else. +read_a: + LDA $4016 + AND #%00000001 + BEQ read_b + ; code for if the a button is pressed +read_b: + LDA $4016 + AND #%00000001 + BEQ read_select + ; code for if the b button is pressed +read_select: + LDA $4016 + AND #%00000001 + BEQ read_start + ; code for if the select button is pressed +read_start: + LDA $4016 + AND #%00000001 + BEQ read_up + ; code for if the start button is pressed +read_up: + LDA $4016 + AND #%00000001 + BEQ read_down + ; code for if the up button is pressed +read_down: + LDA $4016 + AND #%00000001 + BEQ read_left + ; code for if the down button is pressed +read_left: + LDA $4016 + AND #%00000001 + BEQ read_right + ; code for if the left button is pressed +read_right: + LDA $4016 + AND #%00000001 + BEQ end_read_controller1 + ; code for if the right button is pressed + +end_read_controller1: + RTS +``` + +Obviously this could be simplified by putting the reads in a loop (the [snake +game](https://github.com/doy/nes-snake) handles it by shifting and packing all +of the button states into a single byte which the code can query later on), +but that does require more CPU cycles, especially if not all of the buttons +are important. + +In the spirit of continuing with real working code, +[here](/blog/input.s) is a sample program which changes the +background color every time you press A, rather than every second like last +time. Tomorrow, we'll work on drawing sprites! diff --git a/content/blog/writing-an-nes-game-part-4.md b/content/blog/writing-an-nes-game-part-4.md new file mode 100644 index 0000000..87a4257 --- /dev/null +++ b/content/blog/writing-an-nes-game-part-4.md @@ -0,0 +1,186 @@ +--- +title: writing an nes game, part 4 +date: "2014-10-19T20:00:00" +tags: [hacker school, nes] +--- + +# graphics + +Now that we can handle input, it's time to learn how to draw things. All +drawing on the NES is handled by the PPU. The PPU does sprite-based drawing, +meaning that all drawing is two dimensional, and happens in 8x8 blocks. Colors +are determined by a 16-color palette, of which a given sprite can only use +four colors (transparency being one of the colors). There is a background +layer, containing 32x30 tiles, and a set of up to 64 sprites, which can each +be either in front of or behind the background. + +The PPU has its own memory space and mostly just runs on its own, handling the +redrawing automatically every frame. In order to tell it what to do, we have +to load various bits of data into its memory. As mentioned in an earlier post, +the PPU is only capable of doing one thing at a time, so this drawing must +happen at the beginning of the NMI interrupt, when we are guaranteed to be in +VBlank. + +There are four steps involved in drawing a sprite. First, we need the sprite +itself. The pixel data for sprites is stored in the *pattern table*, and is +typically (although not always) stored in CHR-ROM. It contains 16 bytes per +sprite, where each pixel contains two bits of data, so each sprite can contain +at most four colors (including transparent). Since CHR-ROM banks are 8KB +each, this provides enough room for two sets of 256 tiles - typically one set +is used for the background and the other set is used for foreground sprites, +although this is not required. The patterns are laid out in memory as two +chunks of 8 bytes each, where the first 8 bytes correspond to the high bit for +the pixel, and the second 8 bytes correspond to the low bit for the pixel +(each byte representing a row of pixels in the sprite). To help with +generating this sprite data, I have written a script called +[pnm2chr](https://metacpan.org/pod/distribution/Games-NES-SpriteMaker/bin/pnm2chr), +which can convert images in the .PBM/.PGM/.PPM formats (which most image +editors can produce) into CHR-ROM data, so that you can edit sprites in an +image editor instead of a hex editor. + +Once we have the pattern data, we then need the *palette table*, to determine +the actual colors that will be displayed for a given sprite. The way that +colors are determined is actually quite convoluted, going through several +layers of indirection. As a basis, the NES is capable of producing 52 distinct +colors (actually 51, since one of the colors ($0D) is outside of the NTSC +[gamut](https://en.wikipedia.org/wiki/Gamut), and can damage older TVs if +used). From those 52 colors, only 16 can be used at a time (although the 16 +colors can be distinct for the background layer and the sprite layer), and +this set of 16 colors is known as the palette. + +To determine which palette color to use for each pixel in a given background +tile, the two bits from the pattern table are combined with two additional +bits of data from the *attribute table* to create a four bit number (the +pattern bits being the low bits and the attribute bits being the high bits). +The attribute table is a 64-byte chunk of memory which stores two bits for +each 16x16 pixel area of the screen (so each sprite shares the same two-bit +palette with three other sprites in a 2x2 block). The attribute data itself is +packed into bytes such that each byte corresponds to a 4x4 block of sprites. +This is all pretty confusing, so here is a diagram (from the [NES Technical +Documentation](http://emu-docs.org/NES/nestech.txt)) which will hopefully make +things a bit clearer: + + +------------+------------+ + | Square 0 | Square 1 | #0-F represents an 8x8 tile + | #0 #1 | #4 #5 | + | #2 #3 | #6 #7 | Square [x] represents four (4) 8x8 tiles + +------------+------------+ (i.e. a 16x16 pixel grid) + | Square 2 | Square 3 | + | #8 #9 | #C #D | + | #A #B | #E #F | + +------------+------------+ + + Attribute Byte + (Square #) + ---------------- + 33221100 + ||||||+--- Upper two (2) colour bits for Square 0 (Tiles #0,1,2,3) + ||||+----- Upper two (2) colour bits for Square 1 (Tiles #4,5,6,7) + ||+------- Upper two (2) colour bits for Square 2 (Tiles #8,9,A,B) + +--------- Upper two (2) colour bits for Square 3 (Tiles #C,D,E,F) + +For sprites, the upper two bits of the palette index is specified when +requesting the sprite to be drawn. + +The data about which background tile to draw is then stored in the *name +table*. This is a sequence of bytes which correspond to offsets into the +pattern table. For instance, to draw the first pattern in the pattern table, +you would write a $00 to the corresponding location in the name table. The +name table data is the combined with the appropriate attribute table data to +get a palette index, which is then looked up in the palette table to determine +the actual colors to use when drawing the tile. + +The data about which sprites to draw is stored in an entirely separate area of +memory (not part of any address space at all), called the SPR-RAM (sprite +RAM). It is 256 bytes long, and holds four bytes for each of the 64 sprites +that the NES is capable of drawing at any given time. The first byte holds the +vertical offset for the sprite (where the top left of the screen is (0, 0)), +the second byte holds the index into the pattern table for the sprite to draw, +the third byte holds various attributes about the sprite, and the fourth byte +holds the horizontal offset for the sprite. The sprite attributes contain +these bits of data: + +* The low two bits (bits 0 and 1) contain the high bits of the palette index, + as described above. +* Bit 5 is set if the sprite should be drawn behind the background. +* Bit 6 is set if the sprite should be flipped horizontally. +* Bit 7 is set if the sprite should be flipped vertically. + +If you don't need all 64 sprites, you should just move the horizontal and +vertical coordinates such that the sprite is offscreen ($FE or so). + +Now that we have seen all of the different pieces of the PPU memory, here is +how it is all laid out in memory: + + $0000: Pattern Table 0 (typically in CHR-ROM) + $1000: Pattern Table 1 (typically in CHR-ROM) + $2000: Name Table 0 + $23C0: Attribute Table 0 + $2400: Name Table 1 + $27C0: Attribute Table 1 + $2800: (used for mirroring, which I won't discuss here) + $2BC0: (used for mirroring, which I won't discuss here) + $2C00: (used for mirroring, which I won't discuss here) + $2FC0: (used for mirroring, which I won't discuss here) + $3000: (used for mirroring, which I won't discuss here) + $3F00: Palette Table 0 (used for the background) + $3F10: Palette Table 1 (used for sprites) + $3F20: (used for mirroring, which I won't discuss here) + $4000: (used for mirroring, which I won't discuss here) + +So, to draw a background sprite at the top left of the screen, you would write +the sprite index to VRAM address $2000 (assuming default settings). + +The final piece of information necessary to be able to use the PPU is how to +transfer data from main memory into VRAM. This is done via certain +memory-mapped IO addresses. + +First, to copy data into SPR-RAM, you should write all of the sprite data to a +single page (a page is a 256-byte chunk of data whose addresses all start with +the same byte) in RAM, and then write the page number into address $4014 (the +$02 page ($0200-$02FF) is typically used for this purpose). The address to +start writing from can be set by writing a byte to address $2003, and so you +typically want to write $00 into $2003 before starting a full page transfer +with $4014. If you want to write to only certain parts of SPR-RAM, you can do +this via address $2004 - set the base address to write to via $2003 as above, +and then write a sequence of bytes to $2004 to store them into SPR-RAM. + +To copy data into the main VRAM address space, you use the addresses $2006 and +$2007 in the same way that $2003 and $2004 were used for SPR-RAM, except that +you need to write two bytes into $2006 before you start writing to $2007, +since the address space is larger. Since the order of the bytes matters here, +you can read from $2002 to ensure that the next byte written to $2006 will be +the high byte of the address. Note that $2006 is also used for scrolling +(which is based on the last address written to), and so you generally want to +write $2000 back into $2006 at the end of drawing. + +Finally, you need to initialize the PPU in a few ways in order to allow +drawing, which is done via $2000 and $2001. These addresses hold quite a few +different configuration bits, but the most important ones are: + +* Bit 7 of $2000 should be set to enable NMI interrupts (we did this last + time). +* Bit 4 of $2000 should be set to use pattern table 1 instead of 0 for + the background. +* Bit 3 of $2000 should be set to use pattern table 1 instead of 0 for + sprites. +* Bit 0 of $2000 should be set to use name table 1 instead of 0 (this is + actually more complicated due to mirroring, but we won't get into that). +* Bit 4 of $2001 should be set to enable the sprite layer. +* Bit 3 of $2001 should be set to enable the background layer. + +The default pattern and name tables will be fine for now, and so +initialization should set $2000 to $%10000000 and $2001 to $%00011000. + +[Here](/blog/sprites.s) is a sample program which draws a background +and a sprite, and allows you to move the sprite around the background with the +controller D-pad. It will require a CHR-ROM data file with actual patterns in +it, so you can download that from [here]({{urls.media}}/sprites.chr) + +Further reading: +* [NES ASM Tutorial](http://nixw0rm.altervista.org/files/nesasm.pdf) +* [NES technical documentation](http://emu-docs.org/NES/nestech.txt) +* [NES ROM Quickstart](http://sadistech.com/nesromtool/romdoc.html) +* [NES 101](http://hackipedia.org/Platform/Nintendo/NES/tutorial%2c%20NES%20programming%20101/NES101.html) +* [CHR ROM vs. CHR RAM](http://wiki.nesdev.com/w/index.php/CHR_ROM_vs._CHR_RAM) +* [CHR data layout for The Legend of Zelda](http://www.computerarcheology.com/wiki/wiki/NES/Zelda) (Note that unlike what is described above, Zelda stores its pattern data in RAM rather than ROM.) diff --git a/content/contact.md b/content/contact.md new file mode 100644 index 0000000..bba4997 --- /dev/null +++ b/content/contact.md @@ -0,0 +1,7 @@ +--- +title: "contact info" +--- + +* **Email**: doy at tozt dot net +* **Twitter**: @doyster +* **IRC**: doy (on irc.freenode.net) diff --git a/content/internet.md b/content/internet.md new file mode 100644 index 0000000..88005c2 --- /dev/null +++ b/content/internet.md @@ -0,0 +1,12 @@ +--- +title: "me elsewhere on the internet" +--- + +* [Twitter](https://twitter.com/doyster) +* [GitHub](https://github.com/doy) +* [CPAN](https://metacpan.org/author/DOY) +* [last.fm](https://www.last.fm/user/doyster) +* [Project Euler](https://projecteuler.net/index.php?section=profile&profile=doy) +* [Steam](https://steamcommunity.com/id/doyster/) +* [nethack.alt.org](https://alt.org/nethack/plr.php?player=doy) +* [crawl.akrasiac.org](http://crawl.akrasiac.org/scoring/players/doy.html) diff --git a/content/projects.md b/content/projects.md new file mode 100644 index 0000000..1ec7fe3 --- /dev/null +++ b/content/projects.md @@ -0,0 +1,106 @@ +--- +title: "projects i've worked on" +--- + +### conf + +* [Source](https://github.com/doy/conf) + +My (extensive) collection of configuration files. + +### runes + +* [Source](https://github.com/doy/runes) + +Runes is a VT100 terminal emulator for Linux written in C. + +### reply + +* [CPAN](https://metacpan.org/release/Reply) +* [Source](https://github.com/doy/reply) + +Reply is a customizable and lightweight REPL for Perl. It provides features +like pluggable tab completion, automatic class loading and refreshing, history +support, and (through the Carp::Reply module) automatically launching a REPL +when an exception is thrown. It can be easily extended through a powerful +plugin system. + +### Spreadsheet::ParseXLSX + +* [CPAN](https://metacpan.org/release/Spreadsheet-ParseXLSX) +* [Source](https://github.com/doy/spreadsheet-parsexlsx) + +Spreadsheet::ParseXLSX is a Perl module which can read .xlsx files (as +generated by new versions of Microsoft Excel). It handles reading both the data +and formatting from these files. + +### Dungeon Crawl Stone Soup + +* [Website](https://crawl.develz.org/) +* [Source](https://github.com/crawl/crawl) + +I was a member of the development team for Dungeon Crawl Stone Soup, a +roguelike game written in C++ and Lua. I contributed several features +throughout the game, and I was also the release manager for the 0.6 release. + +### Moose + +* [CPAN](https://metacpan.org/release/Moose) +* [Source](https://github.com/moose/Moose) + +I was a member of the development team for Moose, a module which provides +advanced object orientation capabilities for Perl. I was also the release +manager from 2011 – 2012. I am also the maintainer of several widely used Moose +extensions, such as MooseX::NonMoose and MooseX::Aliases. + +### Text::Handlebars + +* [CPAN](https://metacpan.org/release/Text-Handlebars) +* [Source](https://github.com/doy/text-handlebars) + +Text::Handlebars is a port of the Handlebars.js templating language to Perl. It +uses a custom parser on top of the Xslate template engine framework. It +supports nearly the entire feature set of the JavaScript implementation, and we +used it at Infinity Interactive to ease the transition of one of our large web +applications from client side templates to server side templates. + +### OX + +* [CPAN](https://metacpan.org/release/OX) +* [Source](https://github.com/iinteractive/ox) + +OX is a web framework for Perl based on the PSGI specification, which uses the +Bread::Board dependency injection system to manage application components. We +used it internally at Infinity Interactive for many client projects. + +### Plack + +* [Website](https://plackperl.org/) +* [CPAN](https://metacpan.org/release/Plack) +* [Source](https://github.com/plack/Plack) + +I was a member of the core development team for Plack, the reference +implementation of the PSGI specification for Perl web server/application +interaction (similar to Python's WSGI and Ruby's Rack). I have also contributed +to the design of PSGI. + +### Perl + +* [Website](https://perl.org/) +* [Source](https://perl5.git.perl.org/perl.git) + +I was the release manager for the 5.17.1 development release of Perl, and I +have also contributed many bug fixes to the Perl core. In addition, I have +contributed to the initial implementations of the p5-mop project, a prototype +of a new object system for Perl, including features like a meta-object +protocol. + +### TAEB + +* [Website](https://taeb.github.io/) +* [Source](https://github.com/TAEB/TAEB) +* ["Behavioral" AI Source](https://github.com/TAEB/TAEB-AI-Behavioral) + +I was one of the lead framework developers for TAEB, a Perl framework for +programmatic interaction with NetHack. I was also the primary developer for the +leading AI written for TAEB. diff --git a/content/resume.pdf b/content/resume.pdf Binary files differnew file mode 100644 index 0000000..01fc5d5 --- /dev/null +++ b/content/resume.pdf diff --git a/content/resume.tex b/content/resume.tex new file mode 100644 index 0000000..4edab96 --- /dev/null +++ b/content/resume.tex @@ -0,0 +1,198 @@ +% vim:foldmethod=marker commentstring=%%%s +% license {{{ +% This work is licensed under the Creative Commons +% Attribution-NonCommercial-ShareAlike License. To view a copy of this license, +% visit http://creativecommons.org/licenses/by-nc-sa/1.0/ or send a letter to +% Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. +% This file is adapted from Todd Courtesan's resume, at +% http://www.courtesan.com/todd/resume.html +% }}} +% preamble {{{ +\documentclass[letterpaper]{article} +\usepackage{jesse_resume} +\hypersetup{hidelinks} +\setlength{\oddsidemargin}{-0.75in} +\setlength{\evensidemargin}{-0.75in} +\setlength{\textwidth}{8in} +\setlength{\topmargin}{-0.75in} +\setlength{\textheight}{10.5in} +% }}} +\begin{document} +% Header {{{ +\resheader{Jesse Luehrs} + {http://tozt.net/} + {doy@tozt.net\hspace{0.5in}} + {(618) 616-6287} + {70 America St. \#1R} + {Providence, RI 02903} +% }}} +% Education {{{ +\resheading{Education} +\begin{itemize} + % Hacker School {{{ + \item \ressubheading{Hacker School}{New York, NY} + {Student}{September 2014--November 2014} + % }}} + % UIUC {{{ + \item \ressubheading{University of Illinois at Urbana-Champaign, College of Engineering}{Urbana, IL} + {Bachelor of Science in Computer Science with Minor in Mathematics}{August 2004--May 2008} + \begin{minipage}[t]{\textwidth/2-0.2in} + \begin{itemize} + \resitem{Overall GPA: 3.61, Technical GPA: 3.81}\vspace{-7pt} + \resitem{James Scholar in Engineering (2004--2005)}\vspace{4pt} + \end{itemize} + \end{minipage} + \begin{minipage}[t]{\textwidth/2-0.2in} + \begin{itemize} + \resitem{Dean's List (Fall 2004--Fall 2006)}\vspace{-7pt} + \resitem{Graduated with Honors}\vspace{4pt} + \end{itemize} + \end{minipage} + % }}} +\end{itemize} +% }}} +% Work Experience {{{ +\resheading{Work Experience} +\begin{itemize} + % Infinity Interactive {{{ + \item \ressubheading{Infinity Interactive (\url{http://iinteractive.com/})}{Manhasset, NY (telecommuting)} + {Senior Programmer}{February 2010--August 2014} \vspace{6pt} \linebreak + \small{I was in charge of a large, legacy codebase which handles employee + engagement survey registration and reporting, and I have also written + and deployed many smaller sites myself, mostly using Perl. Since we + relied heavily on open source software, a large portion of my time was + also devoted to maintaining various open source projects, as well as + developing new open source software that could be useful in the + future.}\normalsize + % }}} + % UIUC Hydrogeology Lab {{{ + \item \ressubheading{UIUC Hydrogeology Lab (\url{http://www.gwb.com/})}{Urbana, IL} + {Visiting Research Programmer}{February 2006--February 2010} \vspace{6pt} \linebreak + \small{I worked on the Geochemists' Workbench, a geochemistry software suite + written in C++ and Tcl/Tk. I added support for several new image output + formats as well as adding font embedding support to the existing + PostScript format. I also helped add parallel processing support to + several scientific calculations, using OpenMP. I ported our calculation + applications from Windows to Linux, to allow them to be run on large + clusters. Finally, I implemented a testing framework for our calculation + applications using Perl's Test::More.}\normalsize + % }}} +\end{itemize} +% }}} +% Projects {{{ +\resheading{Projects} + +\small{A more complete list of my projects is on my website +(\url{https://tozt.net/projects.html}). All of my personal open source work is +also available on GitHub (\url{https://github.com/doy}), and my Perl open +source work is also available on the CPAN +(\url{https://metacpan.org/author/DOY}).}\normalsize\vspace{-3pt} + +\begin{itemize} + % termcast {{{ + \item \resshortsubheading{Termcast (\url{https://github.com/doy/python-termcast-server})}{2014--present} \vspace{6pt} \linebreak + \small{I wrote a server and client to allow users to stream their terminal + sessions over the network for other people to watch.}\normalsize + % }}} + % libvt100 {{{ + % \item \resshortsubheading{libvt100 (\url{https://github.com/doy/libvt100})}{2014--present} \vspace{6pt} \linebreak + % I am the author of libvt100, a terminal parsing library written in C + % and Lex. I am currently using it in the Termcast server and in Runes, a + % terminal emulator. + % }}} + % Text::Handlebars {{{ + % \item \resshortsubheading{Text::Handlebars (\url{https://github.com/doy/text-handlebars})}{2013--present} \vspace{6pt} \linebreak + % I am the author of Text::Handlebars, a port of the Handlebars.js + % templating language to Perl. It uses a custom parser on top of the + % Xslate template engine framework. It supports nearly the entire feature + % set of the JavaScript implementation, and we used it at Infinity + % Interactive to ease the transition of one of our large web applications + % from client side templates to server side templates. + % }}} + % Reply {{{ + % \item \resshortsubheading{Reply (\url{https://github.com/doy/reply})}{2013--present} \vspace{6pt} \linebreak + % \small{I wrote Reply, a lightweight and extensible REPL for Perl. It includes + % many useful features such as tab completion and history support.}\normalsize + % }}} + % Dungeon Crawl Stone Soup {{{ + \item \resshortsubheading{Dungeon Crawl Stone Soup (\url{http://crawl.develz.org/})}{2009--present} \vspace{6pt} \linebreak + \small{I am a member of the development team for Dungeon Crawl Stone Soup, a + roguelike game written in C++ and Lua. I contributed several features + to the game and was also the release manager for the 0.6 release.}\normalsize + % }}} + % Plack {{{ + % \item \resshortsubheading{Plack (\url{http://plackperl.org/})}{2012--2013} \vspace{6pt} \linebreak + % I am a member of the core development team for PSGI and Plack, the + % specification for Perl web server/application interaction (similar to + % Python's WSGI and Ruby's Rack). + % }}} + % Perl {{{ + \item \resshortsubheading{Perl (\url{http://www.perl.org/})}{2011--2013} \vspace{6pt} \linebreak + \small{I was the release manager for the 5.17.1 development release of Perl, + and I have also contributed many bug fixes. I have also been a lead + developer on the p5-mop project, a prototype of a new object system for + Perl.}\normalsize + % }}} + % OX {{{ + % \item \resshortsubheading{OX (\url{https://github.com/iinteractive/OX})}{2011--present} \vspace{6pt} \linebreak + % I am the lead author of OX, a web framework for Perl based on the PSGI + % specification, which uses the Bread::Board dependency injection system + % to manage application components. We have used it internally at + % Infinity Interactive for many client projects. In addition to writing + % most of the framework itself, I also wrote a series of advent calendar + % posts documenting it, which can be seen at + % \url{http://ox.iinteractive.com/advent/}. + % }}} + % Moose {{{ + \item \resshortsubheading{Moose (\url{http://moose.perl.org/})}{2009--2013} \vspace{6pt} \linebreak + \small{I am a member of the development team for Moose, which provides + advanced object orientation capabilities to Perl. I was also the + release manager from 2011--2012.}\normalsize + % }}} + % TAEB {{{ + \item \resshortsubheading{TAEB (\url{http://taeb.github.io/})}{2008--2011} \vspace{6pt} \linebreak + \small{I was one of the lead framework developers for TAEB, a Perl framework + for programmatic interaction with NetHack. I was also the primary + developer for the leading AI written for TAEB.}\normalsize + % }}} + % Volition {{{ + % \item \resshortsubheading{System for Defining, Documenting and Recording Game Events (\url{http://volition-inc.com/})}{2007--2008} \vspace{6pt} \linebreak + % This is a library written in C which can be added to games in order to + % track arbitrary events and report them to a remote server, for use in + % gameplay testing. This project was completed for Volition as my senior + % project, and was used as part of their testing process for Saints Row + % 2. + % }}} +\end{itemize} +% }}} +% Talks {{{ +\resheading{Talks} + +\small{Slides and videos (where available) for these talks can be found at +\url{http://tozt.net/talks.html}.}\normalsize\vspace{-3pt} + +\begin{itemize} + \item \resshortsubheading{Introduction to Rust (50 min)}{YAPC::NA 2014} \vspace{6pt}\linebreak + \small{This talk describes the Rust programming language, touching on + its major features and design philosophies that make it + interesting.}\normalsize + \item \resshortsubheading{Dependency Injection with Bread::Board (50 min)}{YAPC::NA 2012, YAPC::EU 2012} \vspace{6pt}\linebreak + \small{This talk provides an overview of dependency injection, and + gives concrete examples of it using the Bread::Board module for Perl.}\normalsize + \item \resshortsubheading{OX - the hardest working two letters in Perl (50 min)}{YAPC::NA 2011} \vspace{6pt}\linebreak + \small{This talk describes the OX web framework for Perl, including a + conceptual overview and usage examples.}\normalsize + \item \resshortsubheading{Extending Moose (50 min)}{YAPC::NA 2010} \vspace{6pt}\linebreak + \small{This talk goes into detail describing Moose's meta object + protocol, including what it is, how it works, and how you can extend + it.}\normalsize +\end{itemize} +% }}} +% Skills {{{ +\resheading{Skills} +\begin{description} + \item[Languages:] \small{I am fluent in C, C++, Perl, Lua, and shell, and I am also proficient in Python, JavaScript, HTML/CSS, Scala, Rust, and LaTeX.}\normalsize\vspace{-6pt} + \item[Tools:] \small{Make, vim, git, Firefox}\normalsize +\end{description} +% }}} +\end{document} diff --git a/content/resume.txt b/content/resume.txt new file mode 100644 index 0000000..4c492eb --- /dev/null +++ b/content/resume.txt @@ -0,0 +1,110 @@ +Jesse P Luehrs +============== +Address: 702 W. Green St., Apt #2 + Urbana, IL 61801 +Phone: (618) 616-6287 +Email: doy@tozt.net +Website: http://tozt.net/ + +========= +Education +========= +University of Illinois at Urbana-Champaign, College of Engineering +Urbana, IL +Bachelor of Science in Computer Science +Aug. 2004 - May 2008 +- Overall GPA: 3.61, Technical GPA: 3.81 +- James Scholar in Engineering (2004 - 2005) +- Dean's List (Fall 2004 - Fall 2006) +- Graduated with Honors + +=============== +Work Experience +=============== +UIUC Hydrogeology Lab +Urbana, IL +Visiting Research Programmer +February 2006 - present +- Worked on the Geochemists' Workbench, a geochemistry software suite + written in C++ and Tcl/Tk. +- Added or enhanced support for several different image output formats + including PDF, SVG, and PostScript, including adding TrueType font + embedding to PDF and PostScript files. +- Helped add parallel processing support to several scientific + calculations, using OpenMP. +- Designed a new XML-based configuration file format for our + applications. +- Ported our calculation applications to Linux, to allow them to be run + on large clusters. +- Implemented a testing framework for our calculation applications in + Perl, using Test::More. + +Smile-A-While Amusements +Traveling, Illinois/Indiana/Missouri +Concessions manager +Summer 2004 and 2005 +- Managed several amusement games on the Luehrs' Ideal Rides carnival. + +======== +Projects +======== +Moose (http://moose.perl.org/): 2009 - Present +- Member of the Moose Cabal, the lead development team for Moose. +- Wrote several extensions for Moose, including MooseX::NonMoose, which + allows classes built with Moose to easily interoperate with other + types of classes, and MooseX::Aliases, which allows Moose attributes + to be referred to by different names. + +Bot::Games (http://github.com/doy/bot-games): 2009 - Present +- Bot::Games is an IRC bot framework written in Perl, designed for + multiplayer game moderation. +- Uses Moose extensively to provide a clean and extensible plugin system + for adding games. + +TAEB (http://taeb.sartak.org/): 2008 - Present +- TAEB is a Perl framework (using Moose) for programmatic interaction + with NetHack (http://nethack.org/). +- Primary developer for the leading AI written for TAEB. +- Developed several standalone Perl modules in the course of + development, including Graph::Implicit, which implements several + useful graph algorithms, and IO::Pty::Easy, which provides a simple + read/write interface for interacting with pseudo-terminals. + +Smithy (http://sourceforge.net/projects/smithy/): 2008 +- Smithy is a cross-platform map editor for the Aleph One engine + (http://marathon.sourceforge.net/), written in OCaml. +- Contributed several GUI improvements, including writing custom widgets + using LablGTK. + +System for Defining, Documenting and Recording Game Events + (http://volition-inc.com/): 2007 - 2008 +- This is a library written in C which can be added to games in order to + track arbitrary events and report them to a remote server, for use in + gameplay testing. + +LuaIRC (http://luaforge.net/projects/luairc/): 2006 - 2008 +- LuaIRC is a fully-featured IRC framework written in Lua. +- Supports all standard IRC functionality, including CTCP and DCC. + +====== +Skills +====== +Languages: +- Proficient in C, C++, Perl (CPAN id: DOY), Lua, Bash, OCaml +- Working knowledge of Ruby, Tcl/Tk, JavaScript, LaTeX, HTML/CSS, + PostScript, sed +Operating Systems: +- Linux (Arch, Debian, Gentoo) +- Windows (2000, XP) +Tools: +- Make, Vim, Microsoft Visual Studio, Cygwin, Darcs, Subversion, Git + +========== +Activities +========== +Inline Insomniacs: +- I was the webmaster for the Inline Insomniacs rollerblading club from + 2005 until 2007. +Falling Illini: +- I was a member of the Falling Illini skydiving club from 2007 until + 2008. diff --git a/content/talks.md b/content/talks.md new file mode 100644 index 0000000..3759321 --- /dev/null +++ b/content/talks.md @@ -0,0 +1,15 @@ +--- +title: "talks i've given" +resources: + - name: slides + src: "talks/extending_moose_yapc_na_2010/001.html" +--- + +* YAPC::NA 2014 - [Introduction to Rust](http://www.yapcna.org/yn2014/talk/5360) ([video](http://youtu.be/5EFCMaEbgX4), [transcript](https://github.com/doy/intro-to-rust-yapc-na-2014/blob/master/talk.md), [slides/examples](https://github.com/doy/intro-to-rust-yapc-na-2014/tree/master/examples)) +* YAPC::EU 2012 - [Dependency Injection with Bread::Board](http://act.yapc.eu/ye2012/talk/4181) ([video](http://youtu.be/Xpk7AV90gd8), [slides](/talks/bread_board_yapc_eu_2012.pdf), [source](/talks/bread_board_yapc_eu_2012.key)) +* YAPC::EU 2012 - [TIMTOWTDI in 2012](http://act.yapc.eu/ye2012/talk/4182) +* YAPC::NA 2012 - Dependency Injection with Bread::Board ([video](http://youtu.be/DhhaOQWoOpw), [slides](/talks/bread_board_yapc_na_2012/), [source](/talks/bread_board_yapc_na_2012/slides.vroom)) +* YAPC::NA 2011 - [OX - the hardest working two letters in Perl](https://web.archive.org/web/20110709062708/http://yapc2011.us/yn2011/talk/3251) ([slides](/talks/ox_yapc_na_2011/), [source](/talks/ox_yapc_na_2011/slides.vroom)) +* YAPC::NA 2010 - Extending Moose ([slides](/talks/extending_moose_yapc_na_2010/), [source](/talks/extending_moose_yapc_na_2010/slides.vroom)) <!-- was http://yapc2010.com/yn2010/talk/2646 --> +* YAPC::NA 2010 - App::Termcast - share your terminals! (lightning talk) <!-- was http://yapc2010.com/yn2010/talk/2647 --> +* YAPC::NA 2009 - [Botting NetHack with TAEB (lightning talk)](https://web.archive.org/web/20120323005415/http://yapc10.org/yn2009/talk/2148) diff --git a/content/work.md b/content/work.md new file mode 100644 index 0000000..20bce0e --- /dev/null +++ b/content/work.md @@ -0,0 +1,8 @@ +--- +title: "work" +--- + +I currently work for Stripe and am not actively seeking employment. My (not +particularly up to date) resume can be found here: + +[My resume](/resume.pdf) ([LaTeX source](/resume.tex), [plaintext](/resume.txt)) diff --git a/static/blog/cartridge.jpg b/static/blog/cartridge.jpg Binary files differnew file mode 100644 index 0000000..e6d70ae --- /dev/null +++ b/static/blog/cartridge.jpg diff --git a/static/blog/input.s b/static/blog/input.s new file mode 100644 index 0000000..56ccee5 --- /dev/null +++ b/static/blog/input.s @@ -0,0 +1,135 @@ +.ROMBANKMAP +BANKSTOTAL 2 +BANKSIZE $4000 +BANKS 1 +BANKSIZE $2000 +BANKS 1 +.ENDRO + +.MEMORYMAP +DEFAULTSLOT 0 +SLOTSIZE $4000 +SLOT 0 $C000 +SLOTSIZE $2000 +SLOT 1 $0000 +.ENDME + +.ENUM $00 +sleeping DB +color DB +frame_count DB +.ENDE + + .bank 0 slot 0 + .org $0000 +RESET: + SEI + CLD + LDX #$FF + TXS + INX + STX $2000.w + STX $2001.w + STX $4010.w + LDX #$40 + STX $4017.w + +vblankwait1: + BIT $2002 + BPL vblankwait1 + +clrmem: + LDA #$00 + STA $0000, x + STA $0100, x + STA $0300, x + STA $0400, x + STA $0500, x + STA $0600, x + STA $0700, x + LDA #$FE + STA $0200, x + INX + BNE clrmem + + LDA #%10000001 + STA color + +vblankwait2: + BIT $2002 + BPL vblankwait2 + + LDA #%10000000 + STA $2000 + +loop: + INC sleeping +wait_for_vblank_end: + LDA sleeping + BNE wait_for_vblank_end + + ; controller 1 latch + LDA #$01 + STA $4016 + LDA #$00 + STA $4016 + + ; controller 1 clock, reading the state of the A button + LDA $4016 + AND #%00000001 + BNE change_color + JMP loop_end + ; reading the rest of the buttons is unnecessary, so we don't do it + +change_color: + LDA #$00 + STA frame_count + LDX color + CPX #%10000001 + BEQ turn_green + CPX #%01000001 + BEQ turn_red + +turn_blue: + LDA #%10000001 + STA color + JMP loop_end +turn_green: + LDA #%01000001 + STA color + JMP loop_end +turn_red: + LDA #%00100001 + STA color + +loop_end: + JMP loop + +NMI: + PHA + TXA + PHA + TYA + PHA + + LDA color + STA $2001 + + LDA #$00 + STA sleeping + PLA + TAY + PLA + TAX + PLA + + RTI + + .orga $FFFA + .dw NMI + .dw RESET + .dw 0 + + .bank 1 slot 1 + .org $0000 + .incbin "sprites.chr" diff --git a/static/blog/sprites.chr b/static/blog/sprites.chr Binary files differnew file mode 100644 index 0000000..3713c9c --- /dev/null +++ b/static/blog/sprites.chr diff --git a/static/blog/sprites.s b/static/blog/sprites.s new file mode 100644 index 0000000..5f0b3d9 --- /dev/null +++ b/static/blog/sprites.s @@ -0,0 +1,197 @@ +.ROMBANKMAP +BANKSTOTAL 2 +BANKSIZE $4000 +BANKS 1 +BANKSIZE $2000 +BANKS 1 +.ENDRO + +.MEMORYMAP +DEFAULTSLOT 0 +SLOTSIZE $4000 +SLOT 0 $C000 +SLOTSIZE $2000 +SLOT 1 $0000 +.ENDME + +.ENUM $00 +sleeping DB +.ENDE + +; just use the actual locations in our copy of SPR-RAM rather than zero-page +; addresses, to avoid having to do multiple copies +.define sprite_x $0203 +.define sprite_y $0200 + + .bank 0 slot 0 + .org $0000 +RESET: + SEI + CLD + LDX #$FF + TXS + INX + STX $2000.w + STX $2001.w + STX $4010.w + LDX #$40 + STX $4017.w + +vblankwait1: + BIT $2002 + BPL vblankwait1 + +clrmem: + LDA #$00 + STA $0000, x + STA $0100, x + STA $0300, x + STA $0400, x + STA $0500, x + STA $0600, x + STA $0700, x + LDA #$FE + STA $0200, x + INX + BNE clrmem + + ; start with the sprite near the middle of the screen + LDA #$80 + STA sprite_x + STA sprite_y + +vblankwait2: + BIT $2002 + BPL vblankwait2 + + ; PPU is initialized here, so we can start writing data into it. this is safe + ; because we have not yet enabled drawing, and so we don't have to restrain + ; ourselves to vblank. + + ; first, we load the palettes into $3F00 and $3F10 +load_palettes: + LDA $2002 ; read here so that the next byte written to $2006 is the high + LDA #$3F ; byte of the address + STA $2006 ; write the high byte of the base address + LDA #$00 + STA $2006 ; write the low byte of the base address + LDX #$00 +load_palettes_loop: + LDA palette.w, x + STA $2007 + INX + CPX #$20 ; 16 byte background palette plus 16 byte sprite palette + BNE load_palettes_loop + + ; then we draw the background (doing that here because it won't be changing) + LDA #$20 + STA $2006 ; high byte of the starting address + LDA #$00 + STA $2006 ; low byte of the starting address + LDA #$01 ; pattern index 1 is our background tile + LDX #$04 ; this loop will load $2000-$23FF, which includes the + LDY #$00 ; attribute table range, but we can just adjust the +load_background_loop: ; palette to take that into account + STA $2007 + INY + BNE load_background_loop + DEX + BNE load_background_loop + + ; then we set the unchanging parts of our sprite (the pattern index and the + ; attributes) + LDA #$00 + STA $0201 ; pattern index 0 is our sprite + STA $0202 ; don't need any attributes + + ; enable the PPU + LDA #%10000000 + STA $2000 + LDA #%00011000 + STA $2001 + +loop: + INC sleeping +wait_for_vblank_end: + LDA sleeping + BNE wait_for_vblank_end + + LDA #$01 + STA $4016 + LDA #$00 + STA $4016 + + ; we don't care about a, b, select, start + LDA $4016 + LDA $4016 + LDA $4016 + LDA $4016 + +up: + LDA $4016 + AND #%00000001 + BEQ down + LDX sprite_y.w + DEX + STX sprite_y.w +down: + LDA $4016 + AND #%00000001 + BEQ left + LDX sprite_y.w + INX + STX sprite_y.w +left: + LDA $4016 + AND #%00000001 + BEQ right + LDX sprite_x.w + DEX + STX sprite_x.w +right: + LDA $4016 + AND #%00000001 + BEQ loop_end + LDX sprite_x.w + INX + STX sprite_x.w + +loop_end: + JMP loop + +NMI: + PHA + TXA + PHA + TYA + PHA + + ; now the only thing we need to do here is issue a DMA call to transfer our + ; sprite data into SPR-RAM + LDA #$00 + STA $2003 ; reset the SPR-RAM write offset + LDA #$02 + STA $4014 ; start the DMA transfer from $0200 + + LDA #$00 + STA sleeping + PLA + TAY + PLA + TAX + PLA + + RTI + +palette: + .db $0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30 + .db $0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30,$0F,$30 + + .orga $FFFA + .dw NMI + .dw RESET + .dw 0 + + .bank 1 slot 1 + .org $0000 + .incbin "sprites.chr" diff --git a/static/talks/bread_board_yapc_eu_2012.key b/static/talks/bread_board_yapc_eu_2012.key Binary files differnew file mode 100644 index 0000000..d8e3a5f --- /dev/null +++ b/static/talks/bread_board_yapc_eu_2012.key diff --git a/static/talks/bread_board_yapc_eu_2012.pdf b/static/talks/bread_board_yapc_eu_2012.pdf Binary files differnew file mode 100644 index 0000000..22c82f8 --- /dev/null +++ b/static/talks/bread_board_yapc_eu_2012.pdf diff --git a/static/talks/bread_board_yapc_na_2012/001.html b/static/talks/bread_board_yapc_na_2012/001.html new file mode 100644 index 0000000..76f0738 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/001.html @@ -0,0 +1,51 @@ +<html> +<head> +<title>001</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependency Injection with Bread::Board + + Jesse Luehrs + Infinity Interactive + doy@cpan.org + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/002.html b/static/talks/bread_board_yapc_na_2012/002.html new file mode 100644 index 0000000..026d7d8 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/002.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>002</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "001" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "003.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + A Motivating Example + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/003.pl.html b/static/talks/bread_board_yapc_na_2012/003.pl.html new file mode 100644 index 0000000..d68c9c3 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/003.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>003.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "004.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + +package MyApp; +use MyFramework; + +sub call { + my $self = shift; + + my $dbh = DBI->connect('dbi:mysql:myapp_db'); + my $hello = $dbh->selectall_arrayref('SELECT * FROM my_table')->[0][0]; + + my $template = Template->new(INCLUDE_PATH => 'root/template'); + $template->process('hello.tt', { hello => $hello }, \(my $output)); + + return $output; +} + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/004.pl.html b/static/talks/bread_board_yapc_na_2012/004.pl.html new file mode 100644 index 0000000..83fba78 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/004.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>004.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "003.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + +package MyApp; +use MyFramework; + +has model => (is => 'ro', isa => 'Model', default => sub { Model->new }); +has view => (is => 'ro', isa => 'View', default => sub { View->new }); + +sub call { + my $self = shift; + my $hello = $self->model->get_hello; + return $self->view->render($hello); +} + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/005.pl.html b/static/talks/bread_board_yapc_na_2012/005.pl.html new file mode 100644 index 0000000..6475d93 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/005.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>005.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "004.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre>package MyApp; +use MyFramework; + +has logger => ( + is => 'ro', isa => 'Logger', + default => sub { Logger->new } +); +has model => ( + is => 'ro', isa => 'Model', lazy => 1, + default => sub { Model->new(logger => $_[0]->logger) }, +); +has view => ( + is => 'ro', isa => 'View', lazy => 1, + default => sub { View->new(logger => $_[0]->logger) }, +); + +sub call { + my $self = shift; + my $hello = $self->model->get_hello; + return $self->view->render($hello); +} + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/006.pl.html b/static/talks/bread_board_yapc_na_2012/006.pl.html new file mode 100644 index 0000000..593cc3e --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/006.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>006.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre>package MyApp; +use MyFramework; + +has dsn => (is => 'ro', isa => 'Str', default => 'dbi:mysql:myapp_db'); +has tt_root => (is => 'ro', isa => 'Str', default => 'root/template'); +has logger => (is => 'ro', isa => 'Logger', default => sub {Logger->new}); +has model => ( + is => 'ro', isa => 'Model', lazy => 1, + default => sub { + my $m = Model->connect($_[0]->dsn); + $m->set_logger($_[0]->logger); + return $m; + }, +); +has view => ( + is => 'ro', isa => 'View', lazy => 1, + default => sub { + View->new(logger => $_[0]->logger, tt_root => $_[0]->tt_root); + }, +); + +sub call { ... } + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/007.html b/static/talks/bread_board_yapc_na_2012/007.html new file mode 100644 index 0000000..44137e2 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/007.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>007</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependency Injection + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/007b.html b/static/talks/bread_board_yapc_na_2012/007b.html new file mode 100644 index 0000000..5388b4e --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/007b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>007b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependency Injection + + · a form of inversion of control + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/007c.html b/static/talks/bread_board_yapc_na_2012/007c.html new file mode 100644 index 0000000..2191491 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/007c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>007c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependency Injection + + · a form of inversion of control + · "the inverse of garbage collection" + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/007z.html b/static/talks/bread_board_yapc_na_2012/007z.html new file mode 100644 index 0000000..5656c3b --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/007z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>007z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependency Injection + + · a form of inversion of control + · "the inverse of garbage collection" + · manages object construction + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/008.html b/static/talks/bread_board_yapc_na_2012/008.html new file mode 100644 index 0000000..27b557b --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/008.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>008</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Benefits to Dependency Injection + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/008b.html b/static/talks/bread_board_yapc_na_2012/008b.html new file mode 100644 index 0000000..7cd24c5 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/008b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>008b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Benefits to Dependency Injection + + · provides access to the same object creation code + that your app will actually use + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/008c.html b/static/talks/bread_board_yapc_na_2012/008c.html new file mode 100644 index 0000000..ac32a8d --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/008c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>008c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Benefits to Dependency Injection + + · provides access to the same object creation code + that your app will actually use + · removes need for globals + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/008z.html b/static/talks/bread_board_yapc_na_2012/008z.html new file mode 100644 index 0000000..864c4b8 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/008z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>008z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Benefits to Dependency Injection + + · provides access to the same object creation code + that your app will actually use + · removes need for globals + · testing and reuse + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/009.html b/static/talks/bread_board_yapc_na_2012/009.html new file mode 100644 index 0000000..0a12b58 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/009.html @@ -0,0 +1,53 @@ +<html> +<head> +<title>009</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> Bread::Board + + + + + + + + + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/009z.html b/static/talks/bread_board_yapc_na_2012/009z.html new file mode 100644 index 0000000..0ace083 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/009z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>009z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> Bread::Board + + +-----------------------------------------+ + | A B C D E F G H I J | + |-----------------------------------------| + | o o | 1 o-o-o-o-o v o-o-o-o-o 1 | o o | + | o o | 2 o-o-o-o-o o-o-o-o-o 2 | o o | + | o o | 3 o-o-o-o-o o-o-o-o-o 3 | o o | + | o o | 4 o-o-o-o-o o-o-o-o-o 4 | o o | + | o o | 5 o-o-o-o-o o-o-o-o-o 5 | o o | + | | 6 o-o-o-o-o o-o-o-o-o 6 | | + | o o | 7 o-o-o-o-o o-o-o-o-o 7 | o o | + | o o | 8 o-o-o-o-o o-o-o-o-o 8 | o o | + | o o | 9 o-o-o-o-o o-o-o-o-o 9 | o o | + | o o | 10 o-o-o-o-o o-o-o-o-o 10 | o o | + | o o | 11 o-o-o-o-o o-o-o-o-o 11 | o o | + | | 12 o-o-o-o-o o-o-o-o-o 12 | | + | o o | 13 o-o-o-o-o o-o-o-o-o 13 | o o | + | o o | 14 o-o-o-o-o o-o-o-o-o 14 | o o | + | o o | 15 o-o-o-o-o o-o-o-o-o 15 | o o | + | o o | 16 o-o-o-o-o ^ o-o-o-o-o 16 | o o | + +-----------------------------------------+ + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/010.pl.html b/static/talks/bread_board_yapc_na_2012/010.pl.html new file mode 100644 index 0000000..35f1fa8 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/010.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>010.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> Bread::Board + +my $c = container MyApp => as { + service dsn => 'dbi:mysql:myapp_db'; + service logger => (class => 'Logger', lifecycle => 'Singleton'); + service view => (class => 'View', dependencies => ['logger']); + + service model => ( + class => 'Model', + dependencies => ['logger', 'dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, + ); + service app => ( + class => 'MyApp', + dependencies => ['model', 'view'], + ); +}; +$c->resolve(service => 'app'); + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/011.html b/static/talks/bread_board_yapc_na_2012/011.html new file mode 100644 index 0000000..27a352a --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/011.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>011</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Services + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/011b.html b/static/talks/bread_board_yapc_na_2012/011b.html new file mode 100644 index 0000000..0852e36 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/011b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>011b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Services + + · represent the data you're storing + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/011c.html b/static/talks/bread_board_yapc_na_2012/011c.html new file mode 100644 index 0000000..1acc353 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/011c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>011c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Services + + · represent the data you're storing + · access contents via the ->get method + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/011z.html b/static/talks/bread_board_yapc_na_2012/011z.html new file mode 100644 index 0000000..4c37ffc --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/011z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>011z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "012.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Services + + · represent the data you're storing + · access contents via the ->get method + · three built-in types: + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/012.pl.html b/static/talks/bread_board_yapc_na_2012/012.pl.html new file mode 100644 index 0000000..5fad51f --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/012.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>012.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "013.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::ConstructorInjection + + service view => ( + class => 'View', + ); + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/013.pl.html b/static/talks/bread_board_yapc_na_2012/013.pl.html new file mode 100644 index 0000000..6b70db8 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/013.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>013.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "012.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "014.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + Bread::Board::BlockInjection + + service model => ( + class => 'Model', # optional + block => sub { + my $m = Model->new + $m->initialize; + return $m; + }, + ); + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/014.pl.html b/static/talks/bread_board_yapc_na_2012/014.pl.html new file mode 100644 index 0000000..eb7c53d --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/014.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>014.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "013.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + Bread::Board::Literal + + service dsn => 'dbi:mysql:myapp_db'; + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/015.html b/static/talks/bread_board_yapc_na_2012/015.html new file mode 100644 index 0000000..f87c9e0 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/015.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>015</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "014.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Containers + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/015b.html b/static/talks/bread_board_yapc_na_2012/015b.html new file mode 100644 index 0000000..e02b3b9 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/015b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>015b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Containers + + · hold services and other containers + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/015c.html b/static/talks/bread_board_yapc_na_2012/015c.html new file mode 100644 index 0000000..e732750 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/015c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>015c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Containers + + · hold services and other containers + · access contents via the ->fetch method + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/015z.html b/static/talks/bread_board_yapc_na_2012/015z.html new file mode 100644 index 0000000..52bf73f --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/015z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>015z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Containers + + · hold services and other containers + · access contents via the ->fetch method + · ->resolve is a shortcut method for ->fetch(...)->get + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/016.html b/static/talks/bread_board_yapc_na_2012/016.html new file mode 100644 index 0000000..905afd9 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/016.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>016</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "016b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependencies + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/016b.html b/static/talks/bread_board_yapc_na_2012/016b.html new file mode 100644 index 0000000..8b0e0cd --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/016b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>016b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "016z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependencies + + · tells Bread::Board how your classes are related + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/016z.html b/static/talks/bread_board_yapc_na_2012/016z.html new file mode 100644 index 0000000..d9b1f4a --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/016z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>016z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "016b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "017.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Dependencies + + · tells Bread::Board how your classes are related + · specified as a map of names to service paths + (there are shortcuts for common cases) + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/017.pl.html b/static/talks/bread_board_yapc_na_2012/017.pl.html new file mode 100644 index 0000000..3490107 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/017.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>017.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "016z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "018.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + Dependencies + +service logger => (class => 'Logger'); +service view => ( + class => 'View', + dependencies => ['logger'], +); + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/018.pl.html b/static/talks/bread_board_yapc_na_2012/018.pl.html new file mode 100644 index 0000000..5de2fc0 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/018.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>018.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "017.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Dependencies + +service dsn => 'dbi:mysql:myapp_db'; +service model => ( + class => 'Model', + dependencies => ['dsn'], + block => sub { + my $service = shift; + return Model->connect($service->param('dsn')); + }, +); + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/019.pl.html b/static/talks/bread_board_yapc_na_2012/019.pl.html new file mode 100644 index 0000000..c9ee994 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/019.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>019.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "018.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + Dependencies + +container MyApp => as { + container Model => as { + service dsn => 'dbi:mysql:myapp_db'; + service model => ( + class => 'Model', + dependencies => ['dsn'], + block => sub { + my $service = shift; + return Model->connect($service->param('dsn')); + }, + ); + }; + service app => ( + class => 'MyApp', + dependencies => ['Model/model'], + ); +}; + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/020.html b/static/talks/bread_board_yapc_na_2012/020.html new file mode 100644 index 0000000..88b8442 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/020.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>020</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "020z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + Parameters + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/020z.html b/static/talks/bread_board_yapc_na_2012/020z.html new file mode 100644 index 0000000..2bc3569 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/020z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>020z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "021.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + Parameters + + · like dependencies, but supplied when calling ->get or ->resolve + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/021.pl.html b/static/talks/bread_board_yapc_na_2012/021.pl.html new file mode 100644 index 0000000..dcc1961 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/021.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>021.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "020z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); +}; +$c->resolve(service => 'user', parameters => { name => 'doy' }); + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/022.pl.html b/static/talks/bread_board_yapc_na_2012/022.pl.html new file mode 100644 index 0000000..d502072 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/022.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>022.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "021.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); + service superusers => ( + block => sub { [ $_[0]->param('root') ] }, + dependencies => { + root => { user => { name => 'root' } }, + }, + ); +}; + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/023.pl.html b/static/talks/bread_board_yapc_na_2012/023.pl.html new file mode 100644 index 0000000..f2c19f2 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/023.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>023.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); + service superusers => ( + block => sub { + [ $_[0]->param('user')->inflate(name => 'root') ] + }, + dependencies => ['user'], + ); +}; + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/024.pl.html b/static/talks/bread_board_yapc_na_2012/024.pl.html new file mode 100644 index 0000000..a780d22 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/024.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>024.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "025.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + Parameters + +my $c = container MyApp => as { + service default_username => 'guest'; + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str', optional => 1 }, + }, + dependencies => { + name => 'default_username', + }, + ); +}; +# user with name 'guest' +$c->resolve(service => 'user'); +# user with name 'doy' +$c->resolve(service => 'user', parameters => { name => 'doy' }); + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/025.pl.html b/static/talks/bread_board_yapc_na_2012/025.pl.html new file mode 100644 index 0000000..e39736f --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/025.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>025.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str', optional => 1, default => 'guest' }, + }, + ); +}; +# user with name 'guest' +$c->resolve(service => 'user'); +# user with name 'doy' +$c->resolve(service => 'user', parameters => { name => 'doy' }); + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/026.html b/static/talks/bread_board_yapc_na_2012/026.html new file mode 100644 index 0000000..5dbf9f2 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/026.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>026</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "025.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Lifecycles + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/026b.html b/static/talks/bread_board_yapc_na_2012/026b.html new file mode 100644 index 0000000..ca5f9e4 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/026b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>026b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Lifecycles + + · this is what determines what happens when ->get is called + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/026c.html b/static/talks/bread_board_yapc_na_2012/026c.html new file mode 100644 index 0000000..b1c28c9 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/026c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>026c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Lifecycles + + · this is what determines what happens when ->get is called + · by default, each call to ->get creates a new object + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/026z.html b/static/talks/bread_board_yapc_na_2012/026z.html new file mode 100644 index 0000000..925c234 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/026z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>026z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Lifecycles + + · this is what determines what happens when ->get is called + · by default, each call to ->get creates a new object + · by specifying «lifecycle => 'Singleton'» when creating the service, + the same object will be returned each time + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/027.pl.html b/static/talks/bread_board_yapc_na_2012/027.pl.html new file mode 100644 index 0000000..81900b4 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/027.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>027.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> Bread::Board + +my $c = container MyApp => as { + service dsn => 'dbi:mysql:myapp_db'; + service logger => (class => 'Logger', lifecycle => 'Singleton'); + service view => (class => 'View', dependencies => ['logger']); + + service model => ( + class => 'Model', + dependencies => ['logger', 'dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, + ); + service app => ( + class => 'MyApp', + dependencies => ['model', 'view'], + ); +}; +$c->resolve(service => 'app'); + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/028.html b/static/talks/bread_board_yapc_na_2012/028.html new file mode 100644 index 0000000..19f190a --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/028.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>028</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Best Practices + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/028b.html b/static/talks/bread_board_yapc_na_2012/028b.html new file mode 100644 index 0000000..5ad9534 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/028b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>028b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Best Practices + + · only use containers during initialization + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/028c.html b/static/talks/bread_board_yapc_na_2012/028c.html new file mode 100644 index 0000000..ea57d8e --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/028c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>028c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Best Practices + + · only use containers during initialization + · factories + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/028d.html b/static/talks/bread_board_yapc_na_2012/028d.html new file mode 100644 index 0000000..19c25bb --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/028d.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>028d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Best Practices + + · only use containers during initialization + · factories + · avoid unnecessary subcontainers + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/028z.html b/static/talks/bread_board_yapc_na_2012/028z.html new file mode 100644 index 0000000..b2977dd --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/028z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>028z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "029.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Best Practices + + · only use containers during initialization + · factories + · avoid unnecessary subcontainers + · container classes + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/029.pl.html b/static/talks/bread_board_yapc_na_2012/029.pl.html new file mode 100644 index 0000000..7422143 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/029.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>029.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + +package MyApp::Container; +use Moose; +extends 'Bread::Board::Container'; + +sub BUILD { + container $self => as { + ...; + }; +} + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/030.pl.html b/static/talks/bread_board_yapc_na_2012/030.pl.html new file mode 100644 index 0000000..185c53f --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/030.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>030.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "029.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + +container SomethingElse => as { + container MyApp::Container->new; +}; + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/031.html b/static/talks/bread_board_yapc_na_2012/031.html new file mode 100644 index 0000000..fb86ef0 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/031.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>031</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/031b.html b/static/talks/bread_board_yapc_na_2012/031b.html new file mode 100644 index 0000000..d2e173a --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/031b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>031b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + · defines a mapping from a class_type to a service + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/031c.html b/static/talks/bread_board_yapc_na_2012/031c.html new file mode 100644 index 0000000..af277de --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/031c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>031c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + · defines a mapping from a class_type to a service + · instead of requesting a particular service, you can request an + object of a particular type: $c->resolve(type => 'Model'); + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/031z.html b/static/talks/bread_board_yapc_na_2012/031z.html new file mode 100644 index 0000000..1e245f6 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/031z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>031z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "032.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + · defines a mapping from a class_type to a service + · instead of requesting a particular service, you can request an + object of a particular type: $c->resolve(type => 'Model'); + · with this, we can (mostly) infer the dependencies for a given class + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/032.pl.html b/static/talks/bread_board_yapc_na_2012/032.pl.html new file mode 100644 index 0000000..ec69e85 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/032.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>032.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "033.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + +package Model +use Moose; +has logger => (is => 'ro', isa => 'Logger', required => 1); + +package Logger; +use Moose; + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/033.pl.html b/static/talks/bread_board_yapc_na_2012/033.pl.html new file mode 100644 index 0000000..fe338d6 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/033.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>033.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "032.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + +my $c = container MyApp => as { + typemap Logger => infer; + typemap Model => infer; +}; +$c->resolve(type => 'Model')->logger; # a valid logger object + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/034.html b/static/talks/bread_board_yapc_na_2012/034.html new file mode 100644 index 0000000..7144e36 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/034.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>034</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "033.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "034b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/034b.html b/static/talks/bread_board_yapc_na_2012/034b.html new file mode 100644 index 0000000..fca66b8 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/034b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>034b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "034z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + · required attributes are automatically inferred, becoming either + dependencies (on types) or parameters (if the type doesn't exist + in the typemap) + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/034z.html b/static/talks/bread_board_yapc_na_2012/034z.html new file mode 100644 index 0000000..374ad23 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/034z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>034z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "034b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "035.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Typemaps + + · required attributes are automatically inferred, becoming either + dependencies (on types) or parameters (if the type doesn't exist + in the typemap) + · non-required attributes can still be satisfied by parameters + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/035.pl.html b/static/talks/bread_board_yapc_na_2012/035.pl.html new file mode 100644 index 0000000..944310b --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/035.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>035.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "034z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> Bread::Board::Declare + +package MyApp::Container; +use Moose; +use Bread::Board::Declare; + +has dsn => (is => 'ro', isa => 'Str', value => 'dbi:mysql:myapp_db'); +has logger => (is => 'ro', isa => 'Logger'); +has view => (is => 'ro', isa => 'View', infer => 1); + +has model => ( + is => 'ro', + isa => 'Model', + infer => 1, + dependencies => ['dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, +); +has app => (is => 'ro', isa => 'MyApp', infer => 1); + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/036.html b/static/talks/bread_board_yapc_na_2012/036.html new file mode 100644 index 0000000..a491785 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/036.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>036</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "035.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/036b.html b/static/talks/bread_board_yapc_na_2012/036b.html new file mode 100644 index 0000000..eb25288 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/036b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>036b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · services are declared just by defining attributes + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/036c.html b/static/talks/bread_board_yapc_na_2012/036c.html new file mode 100644 index 0000000..192c71c --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/036c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>036c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · services are declared just by defining attributes + · attribute accessors resolve the service if no value is set + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/036d.html b/static/talks/bread_board_yapc_na_2012/036d.html new file mode 100644 index 0000000..2b56f2d --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/036d.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>036d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · services are declared just by defining attributes + · attribute accessors resolve the service if no value is set + · if the attribute has a value, it is used in dependency resolution + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/036z.html b/static/talks/bread_board_yapc_na_2012/036z.html new file mode 100644 index 0000000..136d5ce --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/036z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>036z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · services are declared just by defining attributes + · attribute accessors resolve the service if no value is set + · if the attribute has a value, it is used in dependency resolution + · MyApp::Container->new(dsn => 'dbi:mysql:other_db')->model + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/037.html b/static/talks/bread_board_yapc_na_2012/037.html new file mode 100644 index 0000000..0868a72 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/037.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>037</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/037b.html b/static/talks/bread_board_yapc_na_2012/037b.html new file mode 100644 index 0000000..bd702a4 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/037b.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>037b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · typemaps are much simplified + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/037c.html b/static/talks/bread_board_yapc_na_2012/037c.html new file mode 100644 index 0000000..44d49f2 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/037c.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>037c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · typemaps are much simplified + · attributes with class_type constraints automatically get a typemap + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/037z.html b/static/talks/bread_board_yapc_na_2012/037z.html new file mode 100644 index 0000000..908bf38 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/037z.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>037z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "038.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Bread::Board::Declare + + · typemaps are much simplified + · attributes with class_type constraints automatically get a typemap + · «infer => 1» infers as many dependencies as possible + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/038.pl.html b/static/talks/bread_board_yapc_na_2012/038.pl.html new file mode 100644 index 0000000..8369221 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/038.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>038.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "039.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + MongoDBx::Bread::Board::Container + +container MyApp => as { + container MongoDBx::Bread::Board::Container->new( + name => 'myapp_db', + host => 'localhost', + database_layout => { + user_db => ['standard_users', 'super_users'], + }, + ); + + service authenticator => ( + class => 'Authenticator', + dependencies => ['myapp_db/user_db/standard_users'], + ); +}; + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/039.pl.html b/static/talks/bread_board_yapc_na_2012/039.pl.html new file mode 100644 index 0000000..9d19129 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/039.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>039.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "038.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "040.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + Catalyst::Plugin::Bread::Board + +package MyApp; +use Catalyst 'Bread::Board'; + +__PACKAGE__->config( + 'Plugin::Bread::Board' => { + container => MyApp::Container->new, + } +); + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/040.pl.html b/static/talks/bread_board_yapc_na_2012/040.pl.html new file mode 100644 index 0000000..5d846c5 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/040.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>040.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "039.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "041" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + OX + +package MyApp; +use OX; + +has model => (is => 'ro', isa => 'Model'); +has view => (is => 'ro', isa => 'View'); + +has controller => ( + is => 'ro', + isa => 'Controller', + infer => 1, +); + +router as { + route '/' => 'controller.index'; +}; + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/041.html b/static/talks/bread_board_yapc_na_2012/041.html new file mode 100644 index 0000000..a550e75 --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/041.html @@ -0,0 +1,48 @@ +<html> +<head> +<title>041</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "040.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + Questions? + + https://metacpan.org/module/Bread::Board + https://metacpan.org/module/Bread::Board::Declare + https://github.com/stevan/OX + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/index.html b/static/talks/bread_board_yapc_na_2012/index.html new file mode 100644 index 0000000..3247c2e --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/index.html @@ -0,0 +1,76 @@ +<html> +<head> +<title>Dependency Injection with Bread::Board</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 13 || keynum == 32) { + window.location = "001.html"; + return false; + } + return true; +} +</script> +<style> +body { + font-family: sans-serif; +} +h4 { + color: #888; +} +</style> +</head> +<body> +<h4>Use SPACEBAR to peruse the slides or click one to start...<h4> +<h1>Dependency Injection with Bread::Board</h1> +<ul> +<li><a href="001.html">Dependency Injection with Bread::Board</a></li> +<li><a href="002.html">A Motivating Example</a></li> +<li><a href="003.pl.html">package MyApp;</a></li> +<li><a href="004.pl.html">package MyApp;</a></li> +<li><a href="005.pl.html">package MyApp;</a></li> +<li><a href="006.pl.html">package MyApp;</a></li> +<li><a href="007.html">Dependency Injection</a></li> +<li><a href="008.html">Benefits to Dependency Injection</a></li> +<li><a href="009.html">Bread::Board</a></li> +<li><a href="010.pl.html">Bread::Board</a></li> +<li><a href="011.html">Services</a></li> +<li><a href="012.pl.html">Bread::Board::ConstructorInjection</a></li> +<li><a href="013.pl.html">Bread::Board::BlockInjection</a></li> +<li><a href="014.pl.html">Bread::Board::Literal</a></li> +<li><a href="015.html">Containers</a></li> +<li><a href="016.html">Dependencies</a></li> +<li><a href="017.pl.html">Dependencies</a></li> +<li><a href="018.pl.html">Dependencies</a></li> +<li><a href="019.pl.html">Dependencies</a></li> +<li><a href="020.html">Parameters</a></li> +<li><a href="021.pl.html">Parameters</a></li> +<li><a href="022.pl.html">Parameters</a></li> +<li><a href="023.pl.html">Parameters</a></li> +<li><a href="024.pl.html">Parameters</a></li> +<li><a href="025.pl.html">Parameters</a></li> +<li><a href="026.html">Lifecycles</a></li> +<li><a href="027.pl.html">Bread::Board</a></li> +<li><a href="028.html">Best Practices</a></li> +<li><a href="029.pl.html">package MyApp::Container;</a></li> +<li><a href="030.pl.html">container SomethingElse => as {</a></li> +<li><a href="031.html">Typemaps</a></li> +<li><a href="032.pl.html">package Model</a></li> +<li><a href="033.pl.html">my $c = container MyApp => as {</a></li> +<li><a href="034.html">Typemaps</a></li> +<li><a href="035.pl.html">Bread::Board::Declare</a></li> +<li><a href="036.html">Bread::Board::Declare</a></li> +<li><a href="037.html">Bread::Board::Declare</a></li> +<li><a href="038.pl.html">MongoDBx::Bread::Board::Container</a></li> +<li><a href="039.pl.html">Catalyst::Plugin::Bread::Board</a></li> +<li><a href="040.pl.html">OX</a></li> +<li><a href="041.html">Questions?</a></li> +</ul> +<p>This presentation was generated by <a +href="http://ingydotnet.github.com/vroom-pm">Vroom</a>. Use <SPACE> key to go +forward and <BACKSPACE> to go backwards. +</p> +</body> diff --git a/static/talks/bread_board_yapc_na_2012/slides.vroom b/static/talks/bread_board_yapc_na_2012/slides.vroom new file mode 100644 index 0000000..404431f --- /dev/null +++ b/static/talks/bread_board_yapc_na_2012/slides.vroom @@ -0,0 +1,508 @@ +# urxvt -fg black -bg white +# setfont 'xft:DejaVuSansMono-19:bold' +# echo 'set exrc' >> ~/.vimrc + +---- config +title: Dependency Injection with Bread::Board +indent: 4 +auto_size: 1 + +---- center +Dependency Injection with Bread::Board + +Jesse Luehrs +Infinity Interactive +doy@cpan.org +---- +== A Motivating Example +---- perl,i0 +package MyApp; +use MyFramework; + +sub call { + my $self = shift; + + my $dbh = DBI->connect('dbi:mysql:myapp_db'); + my $hello = $dbh->selectall_arrayref('SELECT * FROM my_table')->[0][0]; + + my $template = Template->new(INCLUDE_PATH => 'root/template'); + $template->process('hello.tt', { hello => $hello }, \(my $output)); + + return $output; +} +---- perl,i0 +package MyApp; +use MyFramework; + +has model => (is => 'ro', isa => 'Model', default => sub { Model->new }); +has view => (is => 'ro', isa => 'View', default => sub { View->new }); + +sub call { + my $self = shift; + my $hello = $self->model->get_hello; + return $self->view->render($hello); +} +---- perl,i0 +package MyApp; +use MyFramework; + +has logger => ( + is => 'ro', isa => 'Logger', + default => sub { Logger->new } +); +has model => ( + is => 'ro', isa => 'Model', lazy => 1, + default => sub { Model->new(logger => $_[0]->logger) }, +); +has view => ( + is => 'ro', isa => 'View', lazy => 1, + default => sub { View->new(logger => $_[0]->logger) }, +); + +sub call { + my $self = shift; + my $hello = $self->model->get_hello; + return $self->view->render($hello); +} +---- perl,i0 +package MyApp; +use MyFramework; + +has dsn => (is => 'ro', isa => 'Str', default => 'dbi:mysql:myapp_db'); +has tt_root => (is => 'ro', isa => 'Str', default => 'root/template'); +has logger => (is => 'ro', isa => 'Logger', default => sub {Logger->new}); +has model => ( + is => 'ro', isa => 'Model', lazy => 1, + default => sub { + my $m = Model->connect($_[0]->dsn); + $m->set_logger($_[0]->logger); + return $m; + }, +); +has view => ( + is => 'ro', isa => 'View', lazy => 1, + default => sub { + View->new(logger => $_[0]->logger, tt_root => $_[0]->tt_root); + }, +); + +sub call { ... } +---- +Dependency Injection + ++ · a form of inversion of control ++ · "the inverse of garbage collection" ++ · manages object construction +---- +Benefits to Dependency Injection + ++ · provides access to the same object creation code + that your app will actually use ++ · removes need for globals ++ · testing and reuse +---- center,-i1 +== Bread::Board + ++ +-----------------------------------------+ + | A B C D E F G H I J | + |-----------------------------------------| + | o o | 1 o-o-o-o-o v o-o-o-o-o 1 | o o | + | o o | 2 o-o-o-o-o o-o-o-o-o 2 | o o | + | o o | 3 o-o-o-o-o o-o-o-o-o 3 | o o | + | o o | 4 o-o-o-o-o o-o-o-o-o 4 | o o | + | o o | 5 o-o-o-o-o o-o-o-o-o 5 | o o | + | | 6 o-o-o-o-o o-o-o-o-o 6 | | + | o o | 7 o-o-o-o-o o-o-o-o-o 7 | o o | + | o o | 8 o-o-o-o-o o-o-o-o-o 8 | o o | + | o o | 9 o-o-o-o-o o-o-o-o-o 9 | o o | + | o o | 10 o-o-o-o-o o-o-o-o-o 10 | o o | + | o o | 11 o-o-o-o-o o-o-o-o-o 11 | o o | + | | 12 o-o-o-o-o o-o-o-o-o 12 | | + | o o | 13 o-o-o-o-o o-o-o-o-o 13 | o o | + | o o | 14 o-o-o-o-o o-o-o-o-o 14 | o o | + | o o | 15 o-o-o-o-o o-o-o-o-o 15 | o o | + | o o | 16 o-o-o-o-o ^ o-o-o-o-o 16 | o o | + +-----------------------------------------+ +---- perl,i0 +== Bread::Board + +my $c = container MyApp => as { + service dsn => 'dbi:mysql:myapp_db'; + service logger => (class => 'Logger', lifecycle => 'Singleton'); + service view => (class => 'View', dependencies => ['logger']); + + service model => ( + class => 'Model', + dependencies => ['logger', 'dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, + ); + service app => ( + class => 'MyApp', + dependencies => ['model', 'view'], + ); +}; +$c->resolve(service => 'app'); +---- +== Services + ++ · represent the data you're storing ++ · access contents via the ->get method ++ · three built-in types: +---- perl +== Bread::Board::ConstructorInjection + +service view => ( + class => 'View', +); +---- perl +== Bread::Board::BlockInjection + +service model => ( + class => 'Model', # optional + block => sub { + my $m = Model->new + $m->initialize; + return $m; + }, +); +---- perl +== Bread::Board::Literal + +service dsn => 'dbi:mysql:myapp_db'; +---- +== Containers + ++ · hold services and other containers ++ · access contents via the ->fetch method ++ · ->resolve is a shortcut method for ->fetch(...)->get +---- +== Dependencies + ++ · tells Bread::Board how your classes are related ++ · specified as a map of names to service paths + (there are shortcuts for common cases) +---- perl,i0 +== Dependencies + +service logger => (class => 'Logger'); +service view => ( + class => 'View', + dependencies => ['logger'], +); +---- perl,i0 +== Dependencies + +service dsn => 'dbi:mysql:myapp_db'; +service model => ( + class => 'Model', + dependencies => ['dsn'], + block => sub { + my $service = shift; + return Model->connect($service->param('dsn')); + }, +); +---- perl,i0 +== Dependencies + +container MyApp => as { + container Model => as { + service dsn => 'dbi:mysql:myapp_db'; + service model => ( + class => 'Model', + dependencies => ['dsn'], + block => sub { + my $service = shift; + return Model->connect($service->param('dsn')); + }, + ); + }; + service app => ( + class => 'MyApp', + dependencies => ['Model/model'], + ); +}; +---- +== Parameters + ++ · like dependencies, but supplied when calling ->get or ->resolve +---- perl,i0 +== Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); +}; +$c->resolve(service => 'user', parameters => { name => 'doy' }); +---- perl,i0 +== Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); + service superusers => ( + block => sub { [ $_[0]->param('root') ] }, + dependencies => { + root => { user => { name => 'root' } }, + }, + ); +}; +---- perl,i0 +== Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str' }, + }, + ); + service superusers => ( + block => sub { + [ $_[0]->param('user')->inflate(name => 'root') ] + }, + dependencies => ['user'], + ); +}; +---- perl,i0 +== Parameters + +my $c = container MyApp => as { + service default_username => 'guest'; + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str', optional => 1 }, + }, + dependencies => { + name => 'default_username', + }, + ); +}; +# user with name 'guest' +$c->resolve(service => 'user'); +# user with name 'doy' +$c->resolve(service => 'user', parameters => { name => 'doy' }); +---- perl,i0 +== Parameters + +my $c = container MyApp => as { + service user => ( + class => 'User', + parameters => { + name => { isa => 'Str', optional => 1, default => 'guest' }, + }, + ); +}; +# user with name 'guest' +$c->resolve(service => 'user'); +# user with name 'doy' +$c->resolve(service => 'user', parameters => { name => 'doy' }); +---- +== Lifecycles + ++ · this is what determines what happens when ->get is called ++ · by default, each call to ->get creates a new object ++ · by specifying «lifecycle => 'Singleton'» when creating the service, + the same object will be returned each time +---- perl,i0 +== Bread::Board + +my $c = container MyApp => as { + service dsn => 'dbi:mysql:myapp_db'; + service logger => (class => 'Logger', lifecycle => 'Singleton'); + service view => (class => 'View', dependencies => ['logger']); + + service model => ( + class => 'Model', + dependencies => ['logger', 'dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, + ); + service app => ( + class => 'MyApp', + dependencies => ['model', 'view'], + ); +}; +$c->resolve(service => 'app'); +---- +== Best Practices + ++ · only use containers during initialization ++ · factories ++ · avoid unnecessary subcontainers ++ · container classes +---- perl,i0 +package MyApp::Container; +use Moose; +extends 'Bread::Board::Container'; + +sub BUILD { + container $self => as { + ...; + }; +} +---- perl,i0 +container SomethingElse => as { + container MyApp::Container->new; +}; +---- +== Typemaps + ++ · defines a mapping from a class_type to a service ++ · instead of requesting a particular service, you can request an + object of a particular type: $c->resolve(type => 'Model'); ++ · with this, we can (mostly) infer the dependencies for a given class +---- perl,i0 +package Model +use Moose; +has logger => (is => 'ro', isa => 'Logger', required => 1); + +package Logger; +use Moose; +---- perl,i0 +my $c = container MyApp => as { + typemap Logger => infer; + typemap Model => infer; +}; +$c->resolve(type => 'Model')->logger; # a valid logger object +---- +== Typemaps + ++ · required attributes are automatically inferred, becoming either + dependencies (on types) or parameters (if the type doesn't exist + in the typemap) ++ · non-required attributes can still be satisfied by parameters +---- perl,i0 +== Bread::Board::Declare + +package MyApp::Container; +use Moose; +use Bread::Board::Declare; + +has dsn => (is => 'ro', isa => 'Str', value => 'dbi:mysql:myapp_db'); +has logger => (is => 'ro', isa => 'Logger'); +has view => (is => 'ro', isa => 'View', infer => 1); + +has model => ( + is => 'ro', + isa => 'Model', + infer => 1, + dependencies => ['dsn'], + block => sub { + my $m = Model->connect($_[0]->param('dsn')); + $m->set_logger($_[0]->param('logger')); + return $m; + }, +); +has app => (is => 'ro', isa => 'MyApp', infer => 1); +---- +== Bread::Board::Declare + ++ · services are declared just by defining attributes ++ · attribute accessors resolve the service if no value is set ++ · if the attribute has a value, it is used in dependency resolution ++ · MyApp::Container->new(dsn => 'dbi:mysql:other_db')->model +---- +== Bread::Board::Declare + ++ · typemaps are much simplified ++ · attributes with class_type constraints automatically get a typemap ++ · «infer => 1» infers as many dependencies as possible +---- perl,i0 +== MongoDBx::Bread::Board::Container + +container MyApp => as { + container MongoDBx::Bread::Board::Container->new( + name => 'myapp_db', + host => 'localhost', + database_layout => { + user_db => ['standard_users', 'super_users'], + }, + ); + + service authenticator => ( + class => 'Authenticator', + dependencies => ['myapp_db/user_db/standard_users'], + ); +}; +---- perl,i0 +== Catalyst::Plugin::Bread::Board + +package MyApp; +use Catalyst 'Bread::Board'; + +__PACKAGE__->config( + 'Plugin::Bread::Board' => { + container => MyApp::Container->new, + } +); + +---- perl,i0 +== OX + +package MyApp; +use OX; + +has model => (is => 'ro', isa => 'Model'); +has view => (is => 'ro', isa => 'View'); + +has controller => ( + is => 'ro', + isa => 'Controller', + infer => 1, +); + +router as { + route '/' => 'controller.index'; +}; + +---- center +Questions? + +https://metacpan.org/module/Bread::Board +https://metacpan.org/module/Bread::Board::Declare +https://github.com/stevan/OX +---- skip +motivating example (5m, 5s) +- everything inline +- separate model/view classes +- model and view classes both want a logger +- model and logger both want configuration +overview of dependency injection (5m, 1s) +- high level description +- ...??? +bread::board (15m, 4s) +- simple example (translation of intro?) +- services and containers +- dependencies, parameters +- lifecycles +- typemaps +- best practices + - not global - factory classes/closures, etc + - container classes +bread::board::declare (10m) +- show example +- attributes are services are attributes +- automatic typemapping +- subclassing, roles +- subcontainers +real world usage (10m) +- bread::board::container::mongodb +- catalyst::plugin::bread::board +- ox +questions (5m) diff --git a/static/talks/extending_moose_yapc_na_2010/001.html b/static/talks/extending_moose_yapc_na_2010/001.html new file mode 100644 index 0000000..c31f6fb --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/001.html @@ -0,0 +1,45 @@ +<html> +<head> +<title>001</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + Extending Moose + + by Jesse Luehrs (doy at tozt dot net) + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/002.html b/static/talks/extending_moose_yapc_na_2010/002.html new file mode 100644 index 0000000..f19d2f4 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/002.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>002</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "001" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "003" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + motivation + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/003.html b/static/talks/extending_moose_yapc_na_2010/003.html new file mode 100644 index 0000000..190d180 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/003.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>003</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "003b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/003b.html b/static/talks/extending_moose_yapc_na_2010/003b.html new file mode 100644 index 0000000..a9b584a --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/003b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>003b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "003" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "003z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose + + great class builder + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/003z.html b/static/talks/extending_moose_yapc_na_2010/003z.html new file mode 100644 index 0000000..af6fdcf --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/003z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>003z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "003b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "004" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose + + great class builder + + lots of beginner info available + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/004.html b/static/talks/extending_moose_yapc_na_2010/004.html new file mode 100644 index 0000000..2bd886a --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/004.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>004</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "003z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + using only the basic features doesn't gain you much + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/005.pl.html b/static/talks/extending_moose_yapc_na_2010/005.pl.html new file mode 100644 index 0000000..7a80895 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/005.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>005.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "004" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + package Foo; + use base qw(Class::Accessor); + __PACKAGE__->mk_accessors('bar'); + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/006.pl.html b/static/talks/extending_moose_yapc_na_2010/006.pl.html new file mode 100644 index 0000000..4827510 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/006.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>006.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + package Foo; + use Moose; + has bar => (is => 'ro'); + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/007.pl.html b/static/talks/extending_moose_yapc_na_2010/007.pl.html new file mode 100644 index 0000000..4867c18 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/007.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>007.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007z.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + but... + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/007z.pl.html b/static/talks/extending_moose_yapc_na_2010/007z.pl.html new file mode 100644 index 0000000..4f05317 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/007z.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>007z.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + but... + + package Foo; + use Class::Accessor 'antlers'; + has bar => (is => 'ro'); + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/008.html b/static/talks/extending_moose_yapc_na_2010/008.html new file mode 100644 index 0000000..3d6357b --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/008.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>008</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007z.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose gives you more than this + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/008b.html b/static/talks/extending_moose_yapc_na_2010/008b.html new file mode 100644 index 0000000..2770f7d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/008b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>008b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose gives you more than this + + * builders + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/008c.html b/static/talks/extending_moose_yapc_na_2010/008c.html new file mode 100644 index 0000000..b4b5ae0 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/008c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>008c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose gives you more than this + + * builders + * delegation + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/008d.html b/static/talks/extending_moose_yapc_na_2010/008d.html new file mode 100644 index 0000000..68d9c4d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/008d.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>008d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose gives you more than this + + * builders + * delegation + * roles + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/008z.html b/static/talks/extending_moose_yapc_na_2010/008z.html new file mode 100644 index 0000000..3e990be --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/008z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>008z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + moose gives you more than this + + * builders + * delegation + * roles + * etc... + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/009.html b/static/talks/extending_moose_yapc_na_2010/009.html new file mode 100644 index 0000000..465baf3 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/009.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>009</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + but the real power of moose is in extensibility + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/010.html b/static/talks/extending_moose_yapc_na_2010/010.html new file mode 100644 index 0000000..7efb1f3 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/010.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>010</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + typical object systems are defined in terms of, well, object systems + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/010b.html b/static/talks/extending_moose_yapc_na_2010/010b.html new file mode 100644 index 0000000..e997ca4 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/010b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>010b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + typical object systems are defined in terms of, well, object systems + + has input_file => ( + is => 'ro', + isa => File, + coerce => 1, + required => 1, + ); + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/010c.html b/static/talks/extending_moose_yapc_na_2010/010c.html new file mode 100644 index 0000000..c91a322 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/010c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>010c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + typical object systems are defined in terms of, well, object systems + + has input_file => ( + is => 'ro', + isa => File, + coerce => 1, + required => 1, + ); + + wouldn't it be nice to be able to say what we mean? + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/010z.html b/static/talks/extending_moose_yapc_na_2010/010z.html new file mode 100644 index 0000000..b2c5610 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/010z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>010z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + typical object systems are defined in terms of, well, object systems + + has input_file => ( + is => 'ro', + isa => File, + coerce => 1, + required => 1, + ); + + wouldn't it be nice to be able to say what we mean? + + has_file 'input_file'; + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/011.html b/static/talks/extending_moose_yapc_na_2010/011.html new file mode 100644 index 0000000..1b0effd --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/011.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>011</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + code should be written with the intent of communicating with *humans* + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/011b.html b/static/talks/extending_moose_yapc_na_2010/011b.html new file mode 100644 index 0000000..4d7ab4e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/011b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>011b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + code should be written with the intent of communicating with *humans* + + computers are great at figuring out the details on their own + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/011z.html b/static/talks/extending_moose_yapc_na_2010/011z.html new file mode 100644 index 0000000..f7a00ff --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/011z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>011z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "012" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + code should be written with the intent of communicating with *humans* + + computers are great at figuring out the details on their own + + write code in the language of the domain rather than the language of the computer + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/012.html b/static/talks/extending_moose_yapc_na_2010/012.html new file mode 100644 index 0000000..654ab11 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/012.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>012</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "013" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + this has different levels: + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/013.html b/static/talks/extending_moose_yapc_na_2010/013.html new file mode 100644 index 0000000..4d28940 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/013.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>013</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "012" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "014" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + perl: + + a user is a hash table with a key storing the username and a key storing the password, associated with a set of functions for manipulating those hash keys while validating them and ensuring they remain consistent + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/014.html b/static/talks/extending_moose_yapc_na_2010/014.html new file mode 100644 index 0000000..663661d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/014.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>014</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "013" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + moose (by default): + + a user has a readonly string attribute storing the username, and a read/write Authen::Passphrase object storing the password, which password checking is delegated to + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/015.html b/static/talks/extending_moose_yapc_na_2010/015.html new file mode 100644 index 0000000..4e43d87 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/015.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>015</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "014" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + but what we'd really like is: + + a user has a name, and you can ask if its password is correct + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/016.html b/static/talks/extending_moose_yapc_na_2010/016.html new file mode 100644 index 0000000..c43d2b9 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/016.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>016</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "017" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + moose can give us this too + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/017.html b/static/talks/extending_moose_yapc_na_2010/017.html new file mode 100644 index 0000000..f99d50c --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/017.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>017</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "017z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + the mop + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/017z.html b/static/talks/extending_moose_yapc_na_2010/017z.html new file mode 100644 index 0000000..3a57d5c --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/017z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>017z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "017" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "018" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + the mop + + (meta object protocol) + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/018.html b/static/talks/extending_moose_yapc_na_2010/018.html new file mode 100644 index 0000000..90604ea --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/018.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>018</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "017z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + models classes as objects + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/019.html b/static/talks/extending_moose_yapc_na_2010/019.html new file mode 100644 index 0000000..a554692 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/019.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>019</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "018" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + every class is represented by a metaclass + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/019b.html b/static/talks/extending_moose_yapc_na_2010/019b.html new file mode 100644 index 0000000..f988661 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/019b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>019b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + every class is represented by a metaclass + + a normal perl object of the class Moose::Meta::Class + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/019c.html b/static/talks/extending_moose_yapc_na_2010/019c.html new file mode 100644 index 0000000..d1a9e60 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/019c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>019c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + every class is represented by a metaclass + + a normal perl object of the class Moose::Meta::Class + + contains attributes and methods as members (objects of Moose::Meta::Attribute and Moose::Meta::Method) + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/019z.html b/static/talks/extending_moose_yapc_na_2010/019z.html new file mode 100644 index 0000000..e894c8f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/019z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>019z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + every class is represented by a metaclass + + a normal perl object of the class Moose::Meta::Class + + contains attributes and methods as members (objects of Moose::Meta::Attribute and Moose::Meta::Method) + + (other stuff too, but we'll ignore that for now) + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/020.html b/static/talks/extending_moose_yapc_na_2010/020.html new file mode 100644 index 0000000..62ad473 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/020.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>020</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "021" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + Moose::Meta::Class + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/021.html b/static/talks/extending_moose_yapc_na_2010/021.html new file mode 100644 index 0000000..32f72bc --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/021.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>021</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + access these objects through Class->meta (a class method installed by "use Moose") + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/022.html b/static/talks/extending_moose_yapc_na_2010/022.html new file mode 100644 index 0000000..457936d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/022.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>022</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "021" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + class information is stored and manipulated through these objects + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/022b.html b/static/talks/extending_moose_yapc_na_2010/022b.html new file mode 100644 index 0000000..45d26f7 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/022b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>022b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + class information is stored and manipulated through these objects + + * "@ISA = ('Foo')" -> "$meta->superclasses('Foo')" + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/022c.html b/static/talks/extending_moose_yapc_na_2010/022c.html new file mode 100644 index 0000000..10aa7d5 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/022c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>022c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + class information is stored and manipulated through these objects + + * "@ISA = ('Foo')" -> "$meta->superclasses('Foo')" + * "*foo = sub { ... }" -> "$meta->add_method(foo => sub { ... })" + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/022z.html b/static/talks/extending_moose_yapc_na_2010/022z.html new file mode 100644 index 0000000..66ad3f2 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/022z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>022z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + class information is stored and manipulated through these objects + + * "@ISA = ('Foo')" -> "$meta->superclasses('Foo')" + * "*foo = sub { ... }" -> "$meta->add_method(foo => sub { ... })" + * "our $foo = 'bar'" -> "$meta->add_package_symbol('$foo' => 'bar')" + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/023.html b/static/talks/extending_moose_yapc_na_2010/023.html new file mode 100644 index 0000000..40a7d40 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/023.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>023</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + also provides informational methods + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/023b.html b/static/talks/extending_moose_yapc_na_2010/023b.html new file mode 100644 index 0000000..80a061f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/023b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>023b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + also provides informational methods + + * $meta->class_precedence_list + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/023c.html b/static/talks/extending_moose_yapc_na_2010/023c.html new file mode 100644 index 0000000..cc76ea1 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/023c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>023c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + also provides informational methods + + * $meta->class_precedence_list + * $meta->has_method('foo') + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/023z.html b/static/talks/extending_moose_yapc_na_2010/023z.html new file mode 100644 index 0000000..15e1a9f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/023z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>023z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + also provides informational methods + + * $meta->class_precedence_list + * $meta->has_method('foo') + * $meta->does_role('Role') + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/024.html b/static/talks/extending_moose_yapc_na_2010/024.html new file mode 100644 index 0000000..dfe10cf --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/024.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>024</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + and provides other functionality specific to the mop + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/024b.html b/static/talks/extending_moose_yapc_na_2010/024b.html new file mode 100644 index 0000000..bc9e7eb --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/024b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>024b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + and provides other functionality specific to the mop + + * $meta->make_immutable + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/024c.html b/static/talks/extending_moose_yapc_na_2010/024c.html new file mode 100644 index 0000000..eff147a --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/024c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>024c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + and provides other functionality specific to the mop + + * $meta->make_immutable + * $meta->new_object + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/024z.html b/static/talks/extending_moose_yapc_na_2010/024z.html new file mode 100644 index 0000000..4377e46 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/024z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>024z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "025" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + and provides other functionality specific to the mop + + * $meta->make_immutable + * $meta->new_object + * Moose::Meta::Class->create_anon_class + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/025.html b/static/talks/extending_moose_yapc_na_2010/025.html new file mode 100644 index 0000000..8c0fb47 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/025.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>025</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + Moose::Meta::Attribute + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/026.html b/static/talks/extending_moose_yapc_na_2010/026.html new file mode 100644 index 0000000..de53cf0 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/026.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>026</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "025" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + accessed through $meta->get_attribute, etc + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/026b.html b/static/talks/extending_moose_yapc_na_2010/026b.html new file mode 100644 index 0000000..f17a95d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/026b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>026b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + accessed through $meta->get_attribute, etc + + stores data associated with an object + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/026z.html b/static/talks/extending_moose_yapc_na_2010/026z.html new file mode 100644 index 0000000..333da3d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/026z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>026z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + accessed through $meta->get_attribute, etc + + stores data associated with an object + + also handles installing methods associated with accessing that data + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/027.html b/static/talks/extending_moose_yapc_na_2010/027.html new file mode 100644 index 0000000..c005bdb --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/027.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>027</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + informational methods: + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/027b.html b/static/talks/extending_moose_yapc_na_2010/027b.html new file mode 100644 index 0000000..70ac8e8 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/027b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>027b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + informational methods: + + * $meta_attr->get_read_method + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/027z.html b/static/talks/extending_moose_yapc_na_2010/027z.html new file mode 100644 index 0000000..ecd850c --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/027z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>027z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + informational methods: + + * $meta_attr->get_read_method + * $meta_attr->type_constraint + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/028.html b/static/talks/extending_moose_yapc_na_2010/028.html new file mode 100644 index 0000000..7c3bbc4 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/028.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>028</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + accessing data handled by the attribute + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/028z.html b/static/talks/extending_moose_yapc_na_2010/028z.html new file mode 100644 index 0000000..f39c97b --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/028z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>028z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "029" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + accessing data handled by the attribute + + $meta_attr->get_value($obj) + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/029.html b/static/talks/extending_moose_yapc_na_2010/029.html new file mode 100644 index 0000000..b938d34 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/029.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>029</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + Moose::Meta::Method + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/030.html b/static/talks/extending_moose_yapc_na_2010/030.html new file mode 100644 index 0000000..b864827 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/030.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>030</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "029" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + accessed through $meta->get_method, etc + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/030b.html b/static/talks/extending_moose_yapc_na_2010/030b.html new file mode 100644 index 0000000..9863b08 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/030b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>030b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + accessed through $meta->get_method, etc + + represents a method associated with a class + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/030c.html b/static/talks/extending_moose_yapc_na_2010/030c.html new file mode 100644 index 0000000..194dce3 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/030c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>030c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + accessed through $meta->get_method, etc + + represents a method associated with a class + + these are typically introspected from the symbol table, not created explicitly + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/030z.html b/static/talks/extending_moose_yapc_na_2010/030z.html new file mode 100644 index 0000000..f22650e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/030z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>030z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + accessed through $meta->get_method, etc + + represents a method associated with a class + + these are typically introspected from the symbol table, not created explicitly + + they can be created explicitly if necessary; this is how method modifiers work + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/031.html b/static/talks/extending_moose_yapc_na_2010/031.html new file mode 100644 index 0000000..35c8df2 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/031.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>031</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "032" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + so how does this all work? + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/032.html b/static/talks/extending_moose_yapc_na_2010/032.html new file mode 100644 index 0000000..2397bac --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/032.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>032</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "033" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + metacircularity + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/033.html b/static/talks/extending_moose_yapc_na_2010/033.html new file mode 100644 index 0000000..19058b2 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/033.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>033</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "032" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "033b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + metaclasses are instances of the class Moose::Meta::Class + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/033b.html b/static/talks/extending_moose_yapc_na_2010/033b.html new file mode 100644 index 0000000..2b0905d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/033b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>033b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "033" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "033z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + metaclasses are instances of the class Moose::Meta::Class + + but Moose::Meta::Class is itself a class + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/033z.html b/static/talks/extending_moose_yapc_na_2010/033z.html new file mode 100644 index 0000000..41d5355 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/033z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>033z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "033b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + metaclasses are instances of the class Moose::Meta::Class + + but Moose::Meta::Class is itself a class + + so it must have a metaclass + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/034.html b/static/talks/extending_moose_yapc_na_2010/034.html new file mode 100644 index 0000000..a7c2160 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/034.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>034</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "033z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "035" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + this is accomplished by two tricks + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/035.html b/static/talks/extending_moose_yapc_na_2010/035.html new file mode 100644 index 0000000..2cdfecb --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/035.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>035</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "035z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + compiler bootstrapping + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/035z.html b/static/talks/extending_moose_yapc_na_2010/035z.html new file mode 100644 index 0000000..1a8b464 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/035z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>035z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "035" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + compiler bootstrapping + + write a basic version first, replace it with the actual version once the structure is in place + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/036.html b/static/talks/extending_moose_yapc_na_2010/036.html new file mode 100644 index 0000000..b989513 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/036.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>036</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "035z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + Moose::Meta::Class has a metaclass, but it's also a Moose::Meta::Class + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/036z.html b/static/talks/extending_moose_yapc_na_2010/036z.html new file mode 100644 index 0000000..a784d1e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/036z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>036z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + Moose::Meta::Class has a metaclass, but it's also a Moose::Meta::Class + + so Class->meta->meta == Class->meta + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/037.html b/static/talks/extending_moose_yapc_na_2010/037.html new file mode 100644 index 0000000..177075e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/037.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>037</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "038" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + but this is mostly irrelevant + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/038.html b/static/talks/extending_moose_yapc_na_2010/038.html new file mode 100644 index 0000000..717a608 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/038.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>038</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "038z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + the idea to take away is that moose is built on top of moose + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/038z.html b/static/talks/extending_moose_yapc_na_2010/038z.html new file mode 100644 index 0000000..7e99519 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/038z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>038z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "038" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "039" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + the idea to take away is that moose is built on top of moose + + and so it can be extended just like any other moose object + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/039.html b/static/talks/extending_moose_yapc_na_2010/039.html new file mode 100644 index 0000000..3139ede --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/039.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>039</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "038z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "040" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + so we have this foundation, but how can we make this easy to use? + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/040.html b/static/talks/extending_moose_yapc_na_2010/040.html new file mode 100644 index 0000000..6f033bf --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/040.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>040</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "039" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "041" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + Moose::Exporter + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/041.html b/static/talks/extending_moose_yapc_na_2010/041.html new file mode 100644 index 0000000..d7626ff --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/041.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>041</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "040" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "041z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + we have __PACKAGE__->meta->add_attribute(foo => (is => 'ro')) + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/041z.html b/static/talks/extending_moose_yapc_na_2010/041z.html new file mode 100644 index 0000000..867de5e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/041z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>041z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "041" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + we have __PACKAGE__->meta->add_attribute(foo => (is => 'ro')) + + but we'd like "has foo => (is => 'ro')" + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/042.html b/static/talks/extending_moose_yapc_na_2010/042.html new file mode 100644 index 0000000..47d345e --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/042.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>042</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "041z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose::Exporter is a wrapper around Sub::Exporter providing moose-specific functionality + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/042b.html b/static/talks/extending_moose_yapc_na_2010/042b.html new file mode 100644 index 0000000..9b05428 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/042b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>042b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose::Exporter is a wrapper around Sub::Exporter providing moose-specific functionality + + can curry the metaclass into helper functions + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/042z.html b/static/talks/extending_moose_yapc_na_2010/042z.html new file mode 100644 index 0000000..95e78d7 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/042z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>042z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose::Exporter is a wrapper around Sub::Exporter providing moose-specific functionality + + can curry the metaclass into helper functions + + can pass arguments to Moose::Util::MetaRole to customize the metaclasses + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/043.html b/static/talks/extending_moose_yapc_na_2010/043.html new file mode 100644 index 0000000..c9d052f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/043.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>043</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose itself uses Moose::Exporter + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/043b.html b/static/talks/extending_moose_yapc_na_2010/043b.html new file mode 100644 index 0000000..c6f0556 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/043b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>043b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose itself uses Moose::Exporter + + 'has' is a thin wrapper around __PACKAGE__->meta->add_attribute + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/043z.html b/static/talks/extending_moose_yapc_na_2010/043z.html new file mode 100644 index 0000000..cb34df7 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/043z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>043z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "044" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + Moose itself uses Moose::Exporter + + 'has' is a thin wrapper around __PACKAGE__->meta->add_attribute + + read the source to Moose.pm, it's pretty simple + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/044.html b/static/talks/extending_moose_yapc_na_2010/044.html new file mode 100644 index 0000000..f36b3ae --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/044.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>044</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "045" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + so the key here is that all of these metaclasses can be customized, and Moose::Exporter can wrap those customizations to make them pretty + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/045.html b/static/talks/extending_moose_yapc_na_2010/045.html new file mode 100644 index 0000000..cceaf7b --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/045.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>045</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "044" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "046.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + basic extensions don't even need to alter the metaclass + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/046.pl.html b/static/talks/extending_moose_yapc_na_2010/046.pl.html new file mode 100644 index 0000000..d7606ec --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/046.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>046.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "045" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "047.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> package FileAttributes; + use Moose::Exporter; + use MooseX::Types::Path::Class qw(File); + + Moose::Exporter->setup_import_methods( + with_meta => ['has_file'], + ); + + sub has_file { + my ($meta, $name, %options) = @_; + $meta->add_attribute( + $name, + is => 'ro', + isa => File, + coerce => 1, + %options, + ); + } +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/047.pl.html b/static/talks/extending_moose_yapc_na_2010/047.pl.html new file mode 100644 index 0000000..de2cf6b --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/047.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>047.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "046.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "048" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + package Foo; + use Moose; + use FileAttributes; + + has_file 'foo'; + has_file 'bar' => (required => 1); + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/048.html b/static/talks/extending_moose_yapc_na_2010/048.html new file mode 100644 index 0000000..06e902f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/048.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>048</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "047.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "049.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + but altering metaclasses can provide more powerful abstractions + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/049.pl.html b/static/talks/extending_moose_yapc_na_2010/049.pl.html new file mode 100644 index 0000000..cdd2d70 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/049.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>049.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "048" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "050.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + package AtomicMethod::Role::Method; + use Moose::Role; + + around wrap => sub { + my ($orig, $self, $body, @args) = @_; + my $new_body = sub { + warn "locking...\n"; # or something more useful + my @ret = $body->(@_); # TODO: handle context properly + warn "unlocking...\n"; # or something more useful + return @ret; + }; + $self->$orig($new_body, @args); + }; + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/050.pl.html b/static/talks/extending_moose_yapc_na_2010/050.pl.html new file mode 100644 index 0000000..b22e48f --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/050.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>050.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "049.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "050z.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> and make it pretty + + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/050z.pl.html b/static/talks/extending_moose_yapc_na_2010/050z.pl.html new file mode 100644 index 0000000..ca7312d --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/050z.pl.html @@ -0,0 +1,57 @@ +<html> +<head> +<title>050z.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "050.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "051.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> and make it pretty + + package AtomicMethod; + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( + with_meta => [qw(atomic_method)], + ); + + sub _atomic_method_meta { + my ($meta) = @_; + Moose::Meta::Class->create_anon_class( + superclasses => [$meta->method_metaclass], + roles => ['AtomicMethod::Role::Method'], + cache => 1, + )->name; + } + + sub atomic_method { + my ($meta, $name, $code) = @_; + $meta->add_method( + $name => _atomic_method_meta($meta)->wrap( + $code, + name => $name, + package_name => $meta->name, + associated_metaclass => $meta + ), + ); + } +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/051.pl.html b/static/talks/extending_moose_yapc_na_2010/051.pl.html new file mode 100644 index 0000000..cc98caa --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/051.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>051.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "050z.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "052" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + package Foo; + use Moose; + use AtomicMethod; + + atomic_method foo => sub { + warn "in foo\n"; + }; + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/052.html b/static/talks/extending_moose_yapc_na_2010/052.html new file mode 100644 index 0000000..31c2f59 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/052.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>052</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "051.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "053.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + combining metaclass alterations can be even more powerful + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/053.pl.html b/static/talks/extending_moose_yapc_na_2010/053.pl.html new file mode 100644 index 0000000..7eecef6 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/053.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>053.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "052" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "054.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + package Command::Role::Method; + use Moose::Role; + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/054.pl.html b/static/talks/extending_moose_yapc_na_2010/054.pl.html new file mode 100644 index 0000000..b946994 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/054.pl.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>054.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "053.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "055.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> package Command::Role::Class; + use Moose::Role; + + sub get_all_commands { + my ($self) = @_; + grep { Moose::Util::does_role($_, 'Command::Role::Method') } + $self->get_all_methods; + } + + sub has_command { + my ($self, $name) = @_; + my $method = $self->find_method_by_name($name); + return unless $method; + return Moose::Util::does_role($method, 'Command::Role::Method'); + } + + sub get_command { + my ($self, $name) = @_; + my $method = $self->find_method_by_name($name); + return unless $method; + return Moose::Util::does_role($method, 'Command::Role::Method') + ? $method + : (); + } +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/055.pl.html b/static/talks/extending_moose_yapc_na_2010/055.pl.html new file mode 100644 index 0000000..84c098a --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/055.pl.html @@ -0,0 +1,58 @@ +<html> +<head> +<title>055.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "054.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "056.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> package Command; + use Moose::Exporter; + + Moose::Exporter->setup_import_methods( + with_meta => ['command'], + class_metaroles => { + class => ['Command::Role::Class'], + }, + ); + + sub _command_method_meta { + my ($meta) = @_; + Moose::Meta::Class->create_anon_class( + superclasses => [$meta->method_metaclass], + roles => ['Command::Role::Method'], + cache => 1, + )->name; + } + + sub command { + my ($meta, $name, $code) = @_; + $meta->add_method( + $name => _command_method_meta($meta)->wrap( + $code, + name => $name, + package_name => $meta->name, + associated_metaclass => $meta + ), + ); + } +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/056.pl.html b/static/talks/extending_moose_yapc_na_2010/056.pl.html new file mode 100644 index 0000000..1aed6f2 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/056.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>056.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "055.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "057.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + package Foo; + use Moose; + use Command; + + command bar => sub { ... }; + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/057.pl.html b/static/talks/extending_moose_yapc_na_2010/057.pl.html new file mode 100644 index 0000000..e7c7064 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/057.pl.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>057.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "056.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "058" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + package My::App; + use Moose; + use Foo; + + sub run { + my ($self, $cmd) = @_; + if (Foo->meta->has_command($cmd)) { + Foo->new->$cmd; + } + elsif ($cmd eq 'cmdlist') { + print join ', ', map { $_->name } Foo->meta->get_all_commands; + } + } + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/058.html b/static/talks/extending_moose_yapc_na_2010/058.html new file mode 100644 index 0000000..edde0f5 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/058.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>058</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "057.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "059.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + for larger projects, providing a custom exporter can simplify things greatly + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/059.pl.html b/static/talks/extending_moose_yapc_na_2010/059.pl.html new file mode 100644 index 0000000..673f2f2 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/059.pl.html @@ -0,0 +1,59 @@ +<html> +<head> +<title>059.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "058" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "060" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> package Mooose; + use Moose::Exporter; + use MooseX::NonMoose (); + use MooseX::Aliases (); + + my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods( + also => ['MooseX::NonMoose', 'MooseX::Aliases'], + class_metaroles => { + class => ['My::App::Meta::Class'], + }, + ); + + sub import { + strict->import; + warnings->import; + autodie->import; + feature->import(':5.10'); + MooseX::Aliases->import; + goto $import; + } + + sub unimport { + # .... (s/import/unimport/ on the above) + goto $unimport; + } + + sub init_meta { + my ($package, %options) = @_; + die unless $options{for_class}->isa('My::Base::Class'); + goto $init_meta; + } +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/060.html b/static/talks/extending_moose_yapc_na_2010/060.html new file mode 100644 index 0000000..2202e92 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/060.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>060</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "059.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "061" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + the positive side + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/061.html b/static/talks/extending_moose_yapc_na_2010/061.html new file mode 100644 index 0000000..bf9f0b9 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/061.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>061</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "060" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "061b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + these things are easily packaged up into standalone modules + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/061b.html b/static/talks/extending_moose_yapc_na_2010/061b.html new file mode 100644 index 0000000..7fba6d3 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/061b.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>061b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "061" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "061c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + these things are easily packaged up into standalone modules + + * MooseX::FileAttributes + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/061c.html b/static/talks/extending_moose_yapc_na_2010/061c.html new file mode 100644 index 0000000..9681a82 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/061c.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>061c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "061b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "061d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + these things are easily packaged up into standalone modules + + * MooseX::FileAttributes + * MooseX::TransactionalMethods + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/061d.html b/static/talks/extending_moose_yapc_na_2010/061d.html new file mode 100644 index 0000000..603d4d1 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/061d.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>061d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "061c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "061z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + these things are easily packaged up into standalone modules + + * MooseX::FileAttributes + * MooseX::TransactionalMethods + * IM::Engine::Plugin::Commands + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/061z.html b/static/talks/extending_moose_yapc_na_2010/061z.html new file mode 100644 index 0000000..a344b82 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/061z.html @@ -0,0 +1,46 @@ +<html> +<head> +<title>061z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "061d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "062" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + these things are easily packaged up into standalone modules + + * MooseX::FileAttributes + * MooseX::TransactionalMethods + * IM::Engine::Plugin::Commands + * Blawd::OO, TAEB::OO, etc... + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/062.html b/static/talks/extending_moose_yapc_na_2010/062.html new file mode 100644 index 0000000..49d74df --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/062.html @@ -0,0 +1,42 @@ +<html> +<head> +<title>062</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "061z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + any questions? + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/index.html b/static/talks/extending_moose_yapc_na_2010/index.html new file mode 100644 index 0000000..c894505 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/index.html @@ -0,0 +1,97 @@ +<html> +<head> +<title>Extending Moose</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 13 || keynum == 32) { + window.location = "001.html"; + return false; + } + return true; +} +</script> +<style> +body { + font-family: sans-serif; +} +h4 { + color: #888; +} +</style> +</head> +<body> +<h4>Use SPACEBAR to peruse the slides or click one to start...<h4> +<h1>Extending Moose</h1> +<ul> +<li><a href="001.html">Extending Moose</a></li> +<li><a href="002.html">motivation</a></li> +<li><a href="003.html">moose</a></li> +<li><a href="004.html">using only the basic features doesn't gain you much</a></li> +<li><a href="005.pl.html">package Foo;</a></li> +<li><a href="006.pl.html">package Foo;</a></li> +<li><a href="007.pl.html">but...</a></li> +<li><a href="008.html">moose gives you more than this</a></li> +<li><a href="009.html">but the real power of moose is in extensibility</a></li> +<li><a href="010.html">typical object systems are defined in terms of, well, object systems</a></li> +<li><a href="011.html">code should be written with the intent of communicating with *humans*</a></li> +<li><a href="012.html">this has different levels:</a></li> +<li><a href="013.html">perl:</a></li> +<li><a href="014.html">moose (by default):</a></li> +<li><a href="015.html">but what we'd really like is:</a></li> +<li><a href="016.html">moose can give us this too</a></li> +<li><a href="017.html">the mop</a></li> +<li><a href="018.html">models classes as objects</a></li> +<li><a href="019.html">every class is represented by a metaclass</a></li> +<li><a href="020.html">Moose::Meta::Class</a></li> +<li><a href="021.html">access these objects through Class->meta (a class method installed by "use Moose")</a></li> +<li><a href="022.html">class information is stored and manipulated through these objects</a></li> +<li><a href="023.html">also provides informational methods</a></li> +<li><a href="024.html">and provides other functionality specific to the mop</a></li> +<li><a href="025.html">Moose::Meta::Attribute</a></li> +<li><a href="026.html">accessed through $meta->get_attribute, etc</a></li> +<li><a href="027.html">informational methods:</a></li> +<li><a href="028.html">accessing data handled by the attribute</a></li> +<li><a href="029.html">Moose::Meta::Method</a></li> +<li><a href="030.html">accessed through $meta->get_method, etc</a></li> +<li><a href="031.html">so how does this all work?</a></li> +<li><a href="032.html">metacircularity</a></li> +<li><a href="033.html">metaclasses are instances of the class Moose::Meta::Class</a></li> +<li><a href="034.html">this is accomplished by two tricks</a></li> +<li><a href="035.html">compiler bootstrapping</a></li> +<li><a href="036.html">Moose::Meta::Class has a metaclass, but it's also a Moose::Meta::Class</a></li> +<li><a href="037.html">but this is mostly irrelevant</a></li> +<li><a href="038.html">the idea to take away is that moose is built on top of moose</a></li> +<li><a href="039.html">so we have this foundation, but how can we make this easy to use?</a></li> +<li><a href="040.html">Moose::Exporter</a></li> +<li><a href="041.html">we have __PACKAGE__->meta->add_attribute(foo => (is => 'ro'))</a></li> +<li><a href="042.html">Moose::Exporter is a wrapper around Sub::Exporter providing moose-specific functionality</a></li> +<li><a href="043.html">Moose itself uses Moose::Exporter</a></li> +<li><a href="044.html">so the key here is that all of these metaclasses can be customized, and Moose::Exporter can wrap those customizations to make them pretty</a></li> +<li><a href="045.html">basic extensions don't even need to alter the metaclass</a></li> +<li><a href="046.pl.html">package FileAttributes;</a></li> +<li><a href="047.pl.html">package Foo;</a></li> +<li><a href="048.html">but altering metaclasses can provide more powerful abstractions</a></li> +<li><a href="049.pl.html">package AtomicMethod::Role::Method;</a></li> +<li><a href="050.pl.html">and make it pretty</a></li> +<li><a href="051.pl.html">package Foo;</a></li> +<li><a href="052.html">combining metaclass alterations can be even more powerful</a></li> +<li><a href="053.pl.html">package Command::Role::Method;</a></li> +<li><a href="054.pl.html">package Command::Role::Class;</a></li> +<li><a href="055.pl.html">package Command;</a></li> +<li><a href="056.pl.html">package Foo;</a></li> +<li><a href="057.pl.html">package My::App;</a></li> +<li><a href="058.html">for larger projects, providing a custom exporter can simplify things greatly</a></li> +<li><a href="059.pl.html">package Mooose;</a></li> +<li><a href="060.html">the positive side</a></li> +<li><a href="061.html">these things are easily packaged up into standalone modules</a></li> +<li><a href="062.html">any questions?</a></li> +</ul> +<p>This presentation was generated by <a +href="http://ingydotnet.github.com/vroom-pm">Vroom</a>. Use <SPACE> key to go +forward and <BACKSPACE> to go backwards. +</p> +</body> diff --git a/static/talks/extending_moose_yapc_na_2010/slides.vroom b/static/talks/extending_moose_yapc_na_2010/slides.vroom new file mode 100644 index 0000000..7f27df3 --- /dev/null +++ b/static/talks/extending_moose_yapc_na_2010/slides.vroom @@ -0,0 +1,399 @@ +---- config +title: Extending Moose +indent: 8 +height: 18 +width: 69 +skip: 0 + +---- center +Extending Moose + +by Jesse Luehrs (doy at tozt dot net) + +---- +== motivation +---- +moose + ++great class builder + ++lots of beginner info available +---- +using only the basic features doesn't gain you much +---- perl,i4 +package Foo; +use base qw(Class::Accessor); +__PACKAGE__->mk_accessors('bar'); +---- perl,i4 +package Foo; +use Moose; +has bar => (is => 'ro'); +---- perl,i4 +but... + ++package Foo; +use Class::Accessor 'antlers'; +has bar => (is => 'ro'); +---- +moose gives you more than this + ++* builders ++* delegation ++* roles ++* etc... +---- +but the real power of moose is in extensibility +---- +typical object systems are defined in terms of, well, object systems + ++has input_file => ( + is => 'ro', + isa => File, + coerce => 1, + required => 1, +); + ++wouldn't it be nice to be able to say what we mean? + ++has_file 'input_file'; +---- +code should be written with the intent of communicating with *humans* + ++computers are great at figuring out the details on their own + ++write code in the language of the domain rather than the language of the computer +---- +this has different levels: +---- +perl: + +a user is a hash table with a key storing the username and a key storing the password, associated with a set of functions for manipulating those hash keys while validating them and ensuring they remain consistent +---- +moose (by default): + +a user has a readonly string attribute storing the username, and a read/write Authen::Passphrase object storing the password, which password checking is delegated to +---- +but what we'd really like is: + +a user has a name, and you can ask if its password is correct +---- +moose can give us this too +---- +== the mop + ++== (meta object protocol) +---- +models classes as objects +---- +every class is represented by a metaclass + ++a normal perl object of the class Moose::Meta::Class + ++contains attributes and methods as members (objects of Moose::Meta::Attribute and Moose::Meta::Method) + ++(other stuff too, but we'll ignore that for now) +---- +== Moose::Meta::Class +---- +access these objects through Class->meta (a class method installed by "use Moose") +---- +class information is stored and manipulated through these objects + ++* "@ISA = ('Foo')" -> "$meta->superclasses('Foo')" ++* "*foo = sub { ... }" -> "$meta->add_method(foo => sub { ... })" ++* "our $foo = 'bar'" -> "$meta->add_package_symbol('$foo' => 'bar')" +---- +also provides informational methods + ++* $meta->class_precedence_list ++* $meta->has_method('foo') ++* $meta->does_role('Role') +---- +and provides other functionality specific to the mop + ++* $meta->make_immutable ++* $meta->new_object ++* Moose::Meta::Class->create_anon_class +---- +== Moose::Meta::Attribute +---- +accessed through $meta->get_attribute, etc + ++stores data associated with an object + ++also handles installing methods associated with accessing that data +---- +informational methods: + ++* $meta_attr->get_read_method ++* $meta_attr->type_constraint +---- +accessing data handled by the attribute + ++$meta_attr->get_value($obj) +---- +== Moose::Meta::Method +---- +accessed through $meta->get_method, etc + ++represents a method associated with a class + ++these are typically introspected from the symbol table, not created explicitly + ++they can be created explicitly if necessary; this is how method modifiers work +---- +so how does this all work? +---- +== metacircularity +---- +metaclasses are instances of the class Moose::Meta::Class + ++but Moose::Meta::Class is itself a class + ++so it must have a metaclass +---- +this is accomplished by two tricks +---- +compiler bootstrapping + ++write a basic version first, replace it with the actual version once the structure is in place +---- +Moose::Meta::Class has a metaclass, but it's also a Moose::Meta::Class + ++so Class->meta->meta == Class->meta +---- +but this is mostly irrelevant +---- +the idea to take away is that moose is built on top of moose + ++and so it can be extended just like any other moose object +---- +so we have this foundation, but how can we make this easy to use? +---- +== Moose::Exporter +---- +we have __PACKAGE__->meta->add_attribute(foo => (is => 'ro')) + ++but we'd like "has foo => (is => 'ro')" +---- +Moose::Exporter is a wrapper around Sub::Exporter providing moose-specific functionality + ++can curry the metaclass into helper functions + ++can pass arguments to Moose::Util::MetaRole to customize the metaclasses +---- +Moose itself uses Moose::Exporter + ++'has' is a thin wrapper around __PACKAGE__->meta->add_attribute + ++read the source to Moose.pm, it's pretty simple +---- +so the key here is that all of these metaclasses can be customized, and Moose::Exporter can wrap those customizations to make them pretty +---- +basic extensions don't even need to alter the metaclass +---- perl,i4 +package FileAttributes; +use Moose::Exporter; +use MooseX::Types::Path::Class qw(File); + +Moose::Exporter->setup_import_methods( + with_meta => ['has_file'], +); + +sub has_file { + my ($meta, $name, %options) = @_; + $meta->add_attribute( + $name, + is => 'ro', + isa => File, + coerce => 1, + %options, + ); +} +---- perl,i4 +package Foo; +use Moose; +use FileAttributes; + +has_file 'foo'; +has_file 'bar' => (required => 1); +---- +but altering metaclasses can provide more powerful abstractions +---- perl,i4 +package AtomicMethod::Role::Method; +use Moose::Role; + +around wrap => sub { + my ($orig, $self, $body, @args) = @_; + my $new_body = sub { + warn "locking...\n"; # or something more useful + my @ret = $body->(@_); # TODO: handle context properly + warn "unlocking...\n"; # or something more useful + return @ret; + }; + $self->$orig($new_body, @args); +}; +---- perl,i4 +and make it pretty + ++package AtomicMethod; +use Moose::Exporter; + +Moose::Exporter->setup_import_methods( + with_meta => [qw(atomic_method)], +); + +sub _atomic_method_meta { + my ($meta) = @_; + Moose::Meta::Class->create_anon_class( + superclasses => [$meta->method_metaclass], + roles => ['AtomicMethod::Role::Method'], + cache => 1, + )->name; +} + +sub atomic_method { + my ($meta, $name, $code) = @_; + $meta->add_method( + $name => _atomic_method_meta($meta)->wrap( + $code, + name => $name, + package_name => $meta->name, + associated_metaclass => $meta + ), + ); +} +---- perl,i4 +package Foo; +use Moose; +use AtomicMethod; + +atomic_method foo => sub { + warn "in foo\n"; +}; +---- +combining metaclass alterations can be even more powerful +---- perl,i4 +package Command::Role::Method; +use Moose::Role; +---- perl,i4 +package Command::Role::Class; +use Moose::Role; + +sub get_all_commands { + my ($self) = @_; + grep { Moose::Util::does_role($_, 'Command::Role::Method') } + $self->get_all_methods; +} + +sub has_command { + my ($self, $name) = @_; + my $method = $self->find_method_by_name($name); + return unless $method; + return Moose::Util::does_role($method, 'Command::Role::Method'); +} + +sub get_command { + my ($self, $name) = @_; + my $method = $self->find_method_by_name($name); + return unless $method; + return Moose::Util::does_role($method, 'Command::Role::Method') + ? $method + : (); +} +---- perl,i4 +package Command; +use Moose::Exporter; + +Moose::Exporter->setup_import_methods( + with_meta => ['command'], + class_metaroles => { + class => ['Command::Role::Class'], + }, +); + +sub _command_method_meta { + my ($meta) = @_; + Moose::Meta::Class->create_anon_class( + superclasses => [$meta->method_metaclass], + roles => ['Command::Role::Method'], + cache => 1, + )->name; +} + +sub command { + my ($meta, $name, $code) = @_; + $meta->add_method( + $name => _command_method_meta($meta)->wrap( + $code, + name => $name, + package_name => $meta->name, + associated_metaclass => $meta + ), + ); +} +---- perl,i4 +package Foo; +use Moose; +use Command; + +command bar => sub { ... }; +---- perl,i4 +package My::App; +use Moose; +use Foo; + +sub run { + my ($self, $cmd) = @_; + if (Foo->meta->has_command($cmd)) { + Foo->new->$cmd; + } + elsif ($cmd eq 'cmdlist') { + print join ', ', map { $_->name } Foo->meta->get_all_commands; + } +} +---- +for larger projects, providing a custom exporter can simplify things greatly +---- perl,i4 +package Mooose; +use Moose::Exporter; +use MooseX::NonMoose (); +use MooseX::Aliases (); + +my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods( + also => ['MooseX::NonMoose', 'MooseX::Aliases'], + class_metaroles => { + class => ['My::App::Meta::Class'], + }, +); + +sub import { + strict->import; + warnings->import; + autodie->import; + feature->import(':5.10'); + MooseX::Aliases->import; + goto $import; +} + +sub unimport { + # .... (s/import/unimport/ on the above) + goto $unimport; +} + +sub init_meta { + my ($package, %options) = @_; + die unless $options{for_class}->isa('My::Base::Class'); + goto $init_meta; +} +---- +the positive side +---- +these things are easily packaged up into standalone modules + ++* MooseX::FileAttributes ++* MooseX::TransactionalMethods ++* IM::Engine::Plugin::Commands ++* Blawd::OO, TAEB::OO, etc... +---- center +any questions? diff --git a/static/talks/ox_yapc_na_2011/001.html b/static/talks/ox_yapc_na_2011/001.html new file mode 100644 index 0000000..8198145 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/001.html @@ -0,0 +1,55 @@ +<html> +<head> +<title>001</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + OX + The hardest working two letters in Perl + + Jesse Luehrs, Infinity Interactive + + http://github.com/stevan/OX/ + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/002.html b/static/talks/ox_yapc_na_2011/002.html new file mode 100644 index 0000000..a44596b --- /dev/null +++ b/static/talks/ox_yapc_na_2011/002.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>002</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "001" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + history + + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/002b.html b/static/talks/ox_yapc_na_2011/002b.html new file mode 100644 index 0000000..9cbf8e7 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/002b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>002b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + history + + * custom app-specific stuff + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/002c.html b/static/talks/ox_yapc_na_2011/002c.html new file mode 100644 index 0000000..e08e3b4 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/002c.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>002c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + history + + * custom app-specific stuff + * CGI::Application + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/002d.html b/static/talks/ox_yapc_na_2011/002d.html new file mode 100644 index 0000000..a91e7c0 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/002d.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>002d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "002z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + history + + * custom app-specific stuff + * CGI::Application + * Catalyst + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/002z.html b/static/talks/ox_yapc_na_2011/002z.html new file mode 100644 index 0000000..8bd3718 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/002z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>002z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "003" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + history + + * custom app-specific stuff + * CGI::Application + * Catalyst + * Plack + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/003.html b/static/talks/ox_yapc_na_2011/003.html new file mode 100644 index 0000000..28fe492 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/003.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>003</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "002z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "004" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + OX - the web anti-framework + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/004.html b/static/talks/ox_yapc_na_2011/004.html new file mode 100644 index 0000000..d8f8072 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/004.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>004</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "003" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + Stevan + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/005.html b/static/talks/ox_yapc_na_2011/005.html new file mode 100644 index 0000000..0125c6a --- /dev/null +++ b/static/talks/ox_yapc_na_2011/005.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>005</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "004" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + what is OX? + + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/005b.html b/static/talks/ox_yapc_na_2011/005b.html new file mode 100644 index 0000000..1cda024 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/005b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>005b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + what is OX? + + * Bread::Board + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/005c.html b/static/talks/ox_yapc_na_2011/005c.html new file mode 100644 index 0000000..5fcee53 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/005c.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>005c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005d" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + what is OX? + + * Bread::Board + * Path::Router + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/005d.html b/static/talks/ox_yapc_na_2011/005d.html new file mode 100644 index 0000000..4f7227b --- /dev/null +++ b/static/talks/ox_yapc_na_2011/005d.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>005d</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "005z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + what is OX? + + * Bread::Board + * Path::Router + * Plack + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/005z.html b/static/talks/ox_yapc_na_2011/005z.html new file mode 100644 index 0000000..d95cb8c --- /dev/null +++ b/static/talks/ox_yapc_na_2011/005z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>005z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005d" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + what is OX? + + * Bread::Board + * Path::Router + * Plack + * EXPERIMENTAL + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/006.pl.html b/static/talks/ox_yapc_na_2011/006.pl.html new file mode 100644 index 0000000..ffc70df --- /dev/null +++ b/static/talks/ox_yapc_na_2011/006.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>006.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "005z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + # app.psgi + use OX; + + my $counter = 0; + + router as { + route '/' => sub { $counter }; + route '/inc' => sub { ++$counter }; + route '/dec' => sub { --$counter }; + route '/reset' => sub { $counter = 0 }; + route '/set/:num' => sub { $counter = $_[1] }, ( + num => { isa => 'Int' }, + ); + }; + + xo; + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/007.html b/static/talks/ox_yapc_na_2011/007.html new file mode 100644 index 0000000..06c5585 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/007.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>007</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "006.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "007z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + Bread::Board + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/007z.html b/static/talks/ox_yapc_na_2011/007z.html new file mode 100644 index 0000000..23f6e50 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/007z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>007z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + Bread::Board + control your object's construction + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/008.html b/static/talks/ox_yapc_na_2011/008.html new file mode 100644 index 0000000..32a4897 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/008.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>008</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "007z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Bread::Board has containers, containers contain services + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/008b.html b/static/talks/ox_yapc_na_2011/008b.html new file mode 100644 index 0000000..e65cc9f --- /dev/null +++ b/static/talks/ox_yapc_na_2011/008b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>008b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Bread::Board has containers, containers contain services + an OX application is a Bread::Board container + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/008z.html b/static/talks/ox_yapc_na_2011/008z.html new file mode 100644 index 0000000..8146d28 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/008z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>008z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Bread::Board has containers, containers contain services + an OX application is a Bread::Board container + all application objects are services in the container + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/009.html b/static/talks/ox_yapc_na_2011/009.html new file mode 100644 index 0000000..db93d88 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/009.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>009</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "008z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + services can depend on other services + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/009b.html b/static/talks/ox_yapc_na_2011/009b.html new file mode 100644 index 0000000..4b99ddc --- /dev/null +++ b/static/talks/ox_yapc_na_2011/009b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>009b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "009z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + services can depend on other services + dependencies are resolved first + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/009z.html b/static/talks/ox_yapc_na_2011/009z.html new file mode 100644 index 0000000..b0399ec --- /dev/null +++ b/static/talks/ox_yapc_na_2011/009z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>009z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "010" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + services can depend on other services + dependencies are resolved first + passed as constructor parameters to the requested service + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/010.html b/static/talks/ox_yapc_na_2011/010.html new file mode 100644 index 0000000..bc6cc44 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/010.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>010</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "009z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "011.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + at minimum, the router and the app coderef itself are services + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/011.pl.html b/static/talks/ox_yapc_na_2011/011.pl.html new file mode 100644 index 0000000..8ee8bbf --- /dev/null +++ b/static/talks/ox_yapc_na_2011/011.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>011.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "010" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "012.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + package App; + use OX; + + has model => (is => 'ro', isa => 'Model'); + has view => (is => 'ro', isa => 'View'); + has controller => ( + is => 'ro', + isa => 'Controller', + dependencies => ['model', 'view'], + ); + + router as { + route '/' => 'root.index'; + route '/inc' => 'root.inc'; + route '/dec' => 'root.dec'; + route '/reset' => 'root.reset'; + route '/set/:num' => 'root.set', ( + num => { isa => 'Int' }, + ); + }, (root => 'controller'); + + __PACKAGE__->meta->make_immutable; + 1; + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/012.pl.html b/static/talks/ox_yapc_na_2011/012.pl.html new file mode 100644 index 0000000..96cd998 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/012.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>012.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "011.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "013" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + package Controller; + use Moose; + + has view => (is => 'ro', isa => 'View', required => 1); + has model => (is => 'ro', isa => 'Model', required => 1); + + sub index { } + sub inc { my $self = shift; $self->model->inc } + sub dec { my $self = shift; $self->model->dec } + sub reset { my $self = shift; $self->model->reset } + sub set { my $self = shift; $self->model->set($_[1]) } + + around [qw(index inc dec set reset)] => sub { + my $orig = shift; + my $self = shift; + $self->$orig(@_); + return $self->view->render($self->model->count); + }; + + __PACKAGE__->meta->make_immutable; + 1; + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/013.html b/static/talks/ox_yapc_na_2011/013.html new file mode 100644 index 0000000..5f408cd --- /dev/null +++ b/static/talks/ox_yapc_na_2011/013.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>013</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "012.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "013b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Path::Router + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/013b.html b/static/talks/ox_yapc_na_2011/013b.html new file mode 100644 index 0000000..3f95de1 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/013b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>013b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "013" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "013z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Path::Router + translate incoming urls into structured data + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/013z.html b/static/talks/ox_yapc_na_2011/013z.html new file mode 100644 index 0000000..34098f6 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/013z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>013z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "013b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "014.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Path::Router + translate incoming urls into structured data + also translate structured data into urls + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/014.pl.html b/static/talks/ox_yapc_na_2011/014.pl.html new file mode 100644 index 0000000..6a12f3f --- /dev/null +++ b/static/talks/ox_yapc_na_2011/014.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>014.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "013z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + route '/set/:num' => 'root.set', ( + num => { isa => 'Int' }, + ); + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/015.html b/static/talks/ox_yapc_na_2011/015.html new file mode 100644 index 0000000..face2c8 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/015.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>015</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "014.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "015z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + /set/23 -> { num => 23 } + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/015z.html b/static/talks/ox_yapc_na_2011/015z.html new file mode 100644 index 0000000..a1e9d1a --- /dev/null +++ b/static/talks/ox_yapc_na_2011/015z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>015z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + /set/23 -> { num => 23 } + not just the hashref, but also the code to call for this path + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/016.html b/static/talks/ox_yapc_na_2011/016.html new file mode 100644 index 0000000..31324a0 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/016.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>016</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "015z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "017.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + bidirectional + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/017.pl.html b/static/talks/ox_yapc_na_2011/017.pl.html new file mode 100644 index 0000000..33b08a3 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/017.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>017.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "016" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "018" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + $router->uri_for({num => 23}); # '/set/23' + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/018.html b/static/talks/ox_yapc_na_2011/018.html new file mode 100644 index 0000000..c5cf4d8 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/018.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>018</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "017.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "018b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + this translation is controlled by OX, and is pluggable + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/018b.html b/static/talks/ox_yapc_na_2011/018b.html new file mode 100644 index 0000000..a4b87a2 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/018b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>018b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "018" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "018z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + this translation is controlled by OX, and is pluggable + already seen examples + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/018z.html b/static/talks/ox_yapc_na_2011/018z.html new file mode 100644 index 0000000..b95a595 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/018z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>018z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "018b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "019.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + this translation is controlled by OX, and is pluggable + already seen examples + route '/' => sub { ... } + route '/' => 'root.index' + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/019.pl.html b/static/talks/ox_yapc_na_2011/019.pl.html new file mode 100644 index 0000000..c9f6863 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/019.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>019.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "018z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + has root => (is => 'ro', isa => 'Controller'); + + router ['HTTPMethod'] => as { + route '/' => 'root'; + }, (root => 'root'); + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/020.html b/static/talks/ox_yapc_na_2011/020.html new file mode 100644 index 0000000..ac93b16 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/020.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>020</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "019.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "020z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + GET request for '/' will call Controller::get + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/020z.html b/static/talks/ox_yapc_na_2011/020z.html new file mode 100644 index 0000000..7956fa7 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/020z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>020z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "020" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "021" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + GET request for '/' will call Controller::get + POST request for '/' will call Controller::post + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/021.html b/static/talks/ox_yapc_na_2011/021.html new file mode 100644 index 0000000..244af7c --- /dev/null +++ b/static/talks/ox_yapc_na_2011/021.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>021</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "020z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "022.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + this is just the sugar layer + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/022.pl.html b/static/talks/ox_yapc_na_2011/022.pl.html new file mode 100644 index 0000000..fc6ae76 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/022.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>022.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "021" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "023" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + package App; + use OX; + + sub configure_router { ... } + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/023.html b/static/talks/ox_yapc_na_2011/023.html new file mode 100644 index 0000000..2692e5a --- /dev/null +++ b/static/talks/ox_yapc_na_2011/023.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>023</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "022.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "024.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + or, you can replace the router entirely + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/024.pl.html b/static/talks/ox_yapc_na_2011/024.pl.html new file mode 100644 index 0000000..c2ebc7d --- /dev/null +++ b/static/talks/ox_yapc_na_2011/024.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>024.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "023" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "025" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + router 'My::Custom::Router::Class'; + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/025.html b/static/talks/ox_yapc_na_2011/025.html new file mode 100644 index 0000000..8c0336d --- /dev/null +++ b/static/talks/ox_yapc_na_2011/025.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>025</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "024.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + Plack + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/026.html b/static/talks/ox_yapc_na_2011/026.html new file mode 100644 index 0000000..5d47883 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/026.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>026</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "025" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + OX applications provide the Plack::Component api + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/026z.html b/static/talks/ox_yapc_na_2011/026z.html new file mode 100644 index 0000000..f24de1c --- /dev/null +++ b/static/talks/ox_yapc_na_2011/026z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>026z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + OX applications provide the Plack::Component api + ->prepare_app + ->call + ->to_app + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/027.html b/static/talks/ox_yapc_na_2011/027.html new file mode 100644 index 0000000..162825b --- /dev/null +++ b/static/talks/ox_yapc_na_2011/027.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>027</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "026z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + two types of middleware + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/027b.html b/static/talks/ox_yapc_na_2011/027b.html new file mode 100644 index 0000000..d8e2b59 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/027b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>027b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "027z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + two types of middleware + deployment (Stacktrace, ReverseProxy) + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/027z.html b/static/talks/ox_yapc_na_2011/027z.html new file mode 100644 index 0000000..8e97a48 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/027z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>027z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + two types of middleware + deployment (Stacktrace, ReverseProxy) + app-specific (Session) + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/028.html b/static/talks/ox_yapc_na_2011/028.html new file mode 100644 index 0000000..5368ab5 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/028.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>028</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "027z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "029.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + your application class should be able to declare app-specific middleware + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/029.pl.html b/static/talks/ox_yapc_na_2011/029.pl.html new file mode 100644 index 0000000..44456c7 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/029.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>029.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "028" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "030.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + router as { + wrap 'Plack::Middleware::Session'; + route '/' => ...; + }; + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/030.pl.html b/static/talks/ox_yapc_na_2011/030.pl.html new file mode 100644 index 0000000..eb4f260 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/030.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>030.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "029.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + has session_store => ( + is => 'ro', + isa => 'Str', + value => 'File', + ); + + router as { + wrap 'Plack::Middleware::Session' => ( + store => 'session_store', + ); + route '/' => ...; + }; + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/031.html b/static/talks/ox_yapc_na_2011/031.html new file mode 100644 index 0000000..3ac17bc --- /dev/null +++ b/static/talks/ox_yapc_na_2011/031.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>031</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "030.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "032.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + again, this is just the sugar layer + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/032.pl.html b/static/talks/ox_yapc_na_2011/032.pl.html new file mode 100644 index 0000000..f300495 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/032.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>032.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "031" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "033.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + package App; + use Moose; + extends 'OX::Application'; + + sub configure_router { + ... + } + + sub app_from_router { + ... + } + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/033.pl.html b/static/talks/ox_yapc_na_2011/033.pl.html new file mode 100644 index 0000000..927e723 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/033.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>033.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "032.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + package App; + use Moose; + use Bread::Board; + extends 'OX::Application'; + + sub BUILD { + my $self = shift; + container $self => as { + ... + }; + } + + sub configure_router { + ... + } + + sub app_from_router { + ... + } + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/034.html b/static/talks/ox_yapc_na_2011/034.html new file mode 100644 index 0000000..bbebf8f --- /dev/null +++ b/static/talks/ox_yapc_na_2011/034.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>034</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "033.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "035" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + benefits of OX + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/035.html b/static/talks/ox_yapc_na_2011/035.html new file mode 100644 index 0000000..233541a --- /dev/null +++ b/static/talks/ox_yapc_na_2011/035.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>035</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "034" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "035z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + reuse + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/035z.html b/static/talks/ox_yapc_na_2011/035z.html new file mode 100644 index 0000000..3d8e626 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/035z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>035z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "035" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "036.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + reuse + no wrapper classes required + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/036.pl.html b/static/talks/ox_yapc_na_2011/036.pl.html new file mode 100644 index 0000000..f9deefe --- /dev/null +++ b/static/talks/ox_yapc_na_2011/036.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>036.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "035z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "037.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + package App; + use OX; + + has model => (is => 'ro', isa => 'KiokuX::Model'); + has view => (is => 'ro', isa => 'Template'); + + ... + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/037.pl.html b/static/talks/ox_yapc_na_2011/037.pl.html new file mode 100644 index 0000000..d7aab4e --- /dev/null +++ b/static/talks/ox_yapc_na_2011/037.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>037.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "036.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "038" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + package App; + use OX; + + has dsn => (is => 'ro', isa => 'Str', default => 'dbi:sqlite:app.sqlite'); + has root => (is => 'ro', isa => 'Str', default => 'root/templates'); + + has model => ( + is => 'ro', + isa => 'KiokuX::Model', + dependencies => ['dsn'], + ); + has view => ( + is => 'ro', + isa => 'Template', + dependencies => { INCLUDE_PATH => 'root' }, + ); + + ... + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/038.html b/static/talks/ox_yapc_na_2011/038.html new file mode 100644 index 0000000..3ff5b17 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/038.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>038</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "037.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "039.pl" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + application classes are decoupled, and can be used independently + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/039.pl.html b/static/talks/ox_yapc_na_2011/039.pl.html new file mode 100644 index 0000000..8e6d00e --- /dev/null +++ b/static/talks/ox_yapc_na_2011/039.pl.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>039.pl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "038" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "040" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + App->new->model + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/040.html b/static/talks/ox_yapc_na_2011/040.html new file mode 100644 index 0000000..8f4847e --- /dev/null +++ b/static/talks/ox_yapc_na_2011/040.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>040</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "039.pl" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "040b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + get the model object exactly as it would be initialized within the app + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/040b.html b/static/talks/ox_yapc_na_2011/040b.html new file mode 100644 index 0000000..35596db --- /dev/null +++ b/static/talks/ox_yapc_na_2011/040b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>040b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "040" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "040z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + get the model object exactly as it would be initialized within the app + except without initializing the app + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/040z.html b/static/talks/ox_yapc_na_2011/040z.html new file mode 100644 index 0000000..f962fb6 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/040z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>040z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "040b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "041" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + get the model object exactly as it would be initialized within the app + except without initializing the app + very useful for standalone scripts + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/041.html b/static/talks/ox_yapc_na_2011/041.html new file mode 100644 index 0000000..e69e4a1 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/041.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>041</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "040z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + App->new(dsn => 'dbi:SQLite::memory:')->to_app + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/042.html b/static/talks/ox_yapc_na_2011/042.html new file mode 100644 index 0000000..6902569 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/042.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>042</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "041" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + override specific bits of the application at initialization time + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/042b.html b/static/talks/ox_yapc_na_2011/042b.html new file mode 100644 index 0000000..23f6979 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/042b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>042b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "042z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + override specific bits of the application at initialization time + makes testing very easy + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/042z.html b/static/talks/ox_yapc_na_2011/042z.html new file mode 100644 index 0000000..9fd7517 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/042z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>042z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + override specific bits of the application at initialization time + makes testing very easy + simple way to fit in mock objects, or adjust configuration for tests + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/043.html b/static/talks/ox_yapc_na_2011/043.html new file mode 100644 index 0000000..775474b --- /dev/null +++ b/static/talks/ox_yapc_na_2011/043.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>043</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "042z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + the entire structure is just building on existing technology + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/043b.html b/static/talks/ox_yapc_na_2011/043b.html new file mode 100644 index 0000000..287e7fa --- /dev/null +++ b/static/talks/ox_yapc_na_2011/043b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>043b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043c" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + the entire structure is just building on existing technology + applications can use roles and inheritance + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/043c.html b/static/talks/ox_yapc_na_2011/043c.html new file mode 100644 index 0000000..eabf5e3 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/043c.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>043c</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "043z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + the entire structure is just building on existing technology + applications can use roles and inheritance + middleware just works + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/043z.html b/static/talks/ox_yapc_na_2011/043z.html new file mode 100644 index 0000000..6e92ab1 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/043z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>043z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043c" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "044" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + the entire structure is just building on existing technology + applications can use roles and inheritance + middleware just works + components are just normal classes, can be built however you want + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/044.html b/static/talks/ox_yapc_na_2011/044.html new file mode 100644 index 0000000..7815a60 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/044.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>044</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "043z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "045" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/045.html b/static/talks/ox_yapc_na_2011/045.html new file mode 100644 index 0000000..6ec60ab --- /dev/null +++ b/static/talks/ox_yapc_na_2011/045.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>045</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "044" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "045z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + nested applications need work + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/045z.html b/static/talks/ox_yapc_na_2011/045z.html new file mode 100644 index 0000000..6fd7376 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/045z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>045z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "045" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "046" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + nested applications need work + in particular, how can services be shared? + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/046.html b/static/talks/ox_yapc_na_2011/046.html new file mode 100644 index 0000000..15ed09d --- /dev/null +++ b/static/talks/ox_yapc_na_2011/046.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>046</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "045z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "046z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + bread::board subcontainers + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/046z.html b/static/talks/ox_yapc_na_2011/046z.html new file mode 100644 index 0000000..652c406 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/046z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>046z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "046" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "047" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + bread::board subcontainers + need a syntax for this + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/047.html b/static/talks/ox_yapc_na_2011/047.html new file mode 100644 index 0000000..4c34c12 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/047.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>047</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "046z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "047z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + more extensible routebuilders + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/047z.html b/static/talks/ox_yapc_na_2011/047z.html new file mode 100644 index 0000000..552e354 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/047z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>047z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "047" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "048" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + + more extensible routebuilders + want a way to let the controller object control the dispatching + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/048.html b/static/talks/ox_yapc_na_2011/048.html new file mode 100644 index 0000000..6ea3361 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/048.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>048</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "047z" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "048b" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + cleaner underlying foundation + + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/048b.html b/static/talks/ox_yapc_na_2011/048b.html new file mode 100644 index 0000000..91346df --- /dev/null +++ b/static/talks/ox_yapc_na_2011/048b.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>048b</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "048" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "048z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + cleaner underlying foundation + more ways to customize the router + + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/048z.html b/static/talks/ox_yapc_na_2011/048z.html new file mode 100644 index 0000000..d33c48b --- /dev/null +++ b/static/talks/ox_yapc_na_2011/048z.html @@ -0,0 +1,56 @@ +<html> +<head> +<title>048z</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "048b" + ".html"; + return false; + } + if (keynum == 13 || keynum == 32) { + window.location = "049" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + cleaner underlying foundation + more ways to customize the router + more ways to customize the container + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/049.html b/static/talks/ox_yapc_na_2011/049.html new file mode 100644 index 0000000..110f4cf --- /dev/null +++ b/static/talks/ox_yapc_na_2011/049.html @@ -0,0 +1,52 @@ +<html> +<head> +<title>049</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 8) { + window.location = "048z" + ".html"; + return false; + } + if (keynum == 73 || keynum == 105) { + window.location = "index.html"; + return false; + } + return true; +} +</script> +</head> +<body onkeypress="return navigate(event)"> +<pre> + + + + + + + + + + + Any questions? + + http://github.com/stevan/OX/ + + + + + + + + + + + + + + +</pre> +</body> diff --git a/static/talks/ox_yapc_na_2011/index.html b/static/talks/ox_yapc_na_2011/index.html new file mode 100644 index 0000000..3687174 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/index.html @@ -0,0 +1,84 @@ +<html> +<head> +<title>OX - The hardest working two letters in Perl</title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<script> +function navigate(e) { + var keynum = (window.event) // IE + ? e.keyCode + : e.which; + if (keynum == 13 || keynum == 32) { + window.location = "001.html"; + return false; + } + return true; +} +</script> +<style> +body { + font-family: sans-serif; +} +h4 { + color: #888; +} +</style> +</head> +<body> +<h4>Use SPACEBAR to peruse the slides or click one to start...<h4> +<h1>OX - The hardest working two letters in Perl</h1> +<ul> +<li><a href="001.html">OX</a></li> +<li><a href="002.html">history</a></li> +<li><a href="003.html">OX - the web anti-framework</a></li> +<li><a href="004.html">Stevan</a></li> +<li><a href="005.html">what is OX?</a></li> +<li><a href="006.pl.html"># app.psgi</a></li> +<li><a href="007.html">Bread::Board</a></li> +<li><a href="008.html">Bread::Board has containers, containers contain services</a></li> +<li><a href="009.html">services can depend on other services</a></li> +<li><a href="010.html">at minimum, the router and the app coderef itself are services</a></li> +<li><a href="011.pl.html">package App;</a></li> +<li><a href="012.pl.html">package Controller;</a></li> +<li><a href="013.html">Path::Router</a></li> +<li><a href="014.pl.html">route '/set/:num' => 'root.set', (</a></li> +<li><a href="015.html">/set/23 -> { num => 23 }</a></li> +<li><a href="016.html">bidirectional</a></li> +<li><a href="017.pl.html">$router->uri_for({num => 23}); # '/set/23'</a></li> +<li><a href="018.html">this translation is controlled by OX, and is pluggable</a></li> +<li><a href="019.pl.html">has root => (is => 'ro', isa => 'Controller');</a></li> +<li><a href="020.html">GET request for '/' will call Controller::get</a></li> +<li><a href="021.html">this is just the sugar layer</a></li> +<li><a href="022.pl.html">package App;</a></li> +<li><a href="023.html">or, you can replace the router entirely</a></li> +<li><a href="024.pl.html">router 'My::Custom::Router::Class';</a></li> +<li><a href="025.html">Plack</a></li> +<li><a href="026.html">OX applications provide the Plack::Component api</a></li> +<li><a href="027.html">two types of middleware</a></li> +<li><a href="028.html">your application class should be able to declare app-specific middleware</a></li> +<li><a href="029.pl.html">router as {</a></li> +<li><a href="030.pl.html">has session_store => (</a></li> +<li><a href="031.html">again, this is just the sugar layer</a></li> +<li><a href="032.pl.html">package App;</a></li> +<li><a href="033.pl.html">package App;</a></li> +<li><a href="034.html">benefits of OX</a></li> +<li><a href="035.html">reuse</a></li> +<li><a href="036.pl.html">package App;</a></li> +<li><a href="037.pl.html">package App;</a></li> +<li><a href="038.html">application classes are decoupled, and can be used independently</a></li> +<li><a href="039.pl.html">App->new->model</a></li> +<li><a href="040.html">get the model object exactly as it would be initialized within the app</a></li> +<li><a href="041.html">App->new(dsn => 'dbi:SQLite::memory:')->to_app</a></li> +<li><a href="042.html">override specific bits of the application at initialization time</a></li> +<li><a href="043.html">the entire structure is just building on existing technology</a></li> +<li><a href="044.html">TODO</a></li> +<li><a href="045.html">nested applications need work</a></li> +<li><a href="046.html">bread::board subcontainers</a></li> +<li><a href="047.html">more extensible routebuilders</a></li> +<li><a href="048.html">cleaner underlying foundation</a></li> +<li><a href="049.html">Any questions?</a></li> +</ul> +<p>This presentation was generated by <a +href="http://ingydotnet.github.com/vroom-pm">Vroom</a>. Use <SPACE> key to go +forward and <BACKSPACE> to go backwards. +</p> +</body> diff --git a/static/talks/ox_yapc_na_2011/slides.vroom b/static/talks/ox_yapc_na_2011/slides.vroom new file mode 100644 index 0000000..c013537 --- /dev/null +++ b/static/talks/ox_yapc_na_2011/slides.vroom @@ -0,0 +1,366 @@ +---- config +title: OX - The hardest working two letters in Perl +indent: 4 +height: 28 +width: 80 +skip: 0 +vimrc: colorscheme zellner + +---- center + +OX +The hardest working two letters in Perl + +Jesse Luehrs, Infinity Interactive + +http://github.com/stevan/OX/ + +---- + +== history + ++* custom app-specific stuff ++* CGI::Application ++* Catalyst ++* Plack + +---- center + +OX - the web anti-framework + +---- center + +== Stevan + +---- + +== what is OX? + ++* Bread::Board ++* Path::Router ++* Plack ++* EXPERIMENTAL + +---- perl,i4 + +---- include app.psgi + +---- + +Bread::Board ++control your object's construction + +---- + +Bread::Board has containers, containers contain services ++an OX application is a Bread::Board container ++all application objects are services in the container + +---- + +services can depend on other services ++dependencies are resolved first ++passed as constructor parameters to the requested service + +---- + +at minimum, the router and the app coderef itself are services + +---- perl,i4 + +package App; +use OX; + +has model => (is => 'ro', isa => 'Model'); +has view => (is => 'ro', isa => 'View'); +has controller => ( + is => 'ro', + isa => 'Controller', + dependencies => ['model', 'view'], +); + +router as { + route '/' => 'root.index'; + route '/inc' => 'root.inc'; + route '/dec' => 'root.dec'; + route '/reset' => 'root.reset'; + route '/set/:num' => 'root.set', ( + num => { isa => 'Int' }, + ); +}, (root => 'controller'); + +__PACKAGE__->meta->make_immutable; +1; + +---- perl,i4 + +package Controller; +use Moose; + +has view => (is => 'ro', isa => 'View', required => 1); +has model => (is => 'ro', isa => 'Model', required => 1); + +sub index { } +sub inc { my $self = shift; $self->model->inc } +sub dec { my $self = shift; $self->model->dec } +sub reset { my $self = shift; $self->model->reset } +sub set { my $self = shift; $self->model->set($_[1]) } + +around [qw(index inc dec set reset)] => sub { + my $orig = shift; + my $self = shift; + $self->$orig(@_); + return $self->view->render($self->model->count); +}; + +__PACKAGE__->meta->make_immutable; +1; + +---- + +Path::Router ++translate incoming urls into structured data ++also translate structured data into urls + +---- perl,i4 + +route '/set/:num' => 'root.set', ( + num => { isa => 'Int' }, +); + +---- + +/set/23 -> { num => 23 } ++not just the hashref, but also the code to call for this path + +---- + +bidirectional + +---- perl,i4 + +$router->uri_for({num => 23}); # '/set/23' + +---- + +this translation is controlled by OX, and is pluggable ++already seen examples ++route '/' => sub { ... } +route '/' => 'root.index' + +---- perl,i4 + +has root => (is => 'ro', isa => 'Controller'); + +router ['HTTPMethod'] => as { + route '/' => 'root'; +}, (root => 'root'); + +---- + +GET request for '/' will call Controller::get ++POST request for '/' will call Controller::post + +---- + +this is just the sugar layer + +---- perl,i4 + +package App; +use OX; + +sub configure_router { ... } + +---- + +or, you can replace the router entirely + +---- perl,i4 + +router 'My::Custom::Router::Class'; + +---- + +Plack + +---- + +OX applications provide the Plack::Component api ++->prepare_app +->call +->to_app + +---- + +two types of middleware ++deployment (Stacktrace, ReverseProxy) ++app-specific (Session) + +---- + +your application class should be able to declare app-specific middleware + +---- perl,i4 + +router as { + wrap 'Plack::Middleware::Session'; + route '/' => ...; +}; + +---- perl,i4 + +has session_store => ( + is => 'ro', + isa => 'Str', + value => 'File', +); + +router as { + wrap 'Plack::Middleware::Session' => ( + store => 'session_store', + ); + route '/' => ...; +}; + +---- + +again, this is just the sugar layer + +---- perl,i4 + +package App; +use Moose; +extends 'OX::Application'; + +sub configure_router { + ... +} + +sub app_from_router { + ... +} + +---- perl,i4 + +package App; +use Moose; +use Bread::Board; +extends 'OX::Application'; + +sub BUILD { + my $self = shift; + container $self => as { + ... + }; +} + +sub configure_router { + ... +} + +sub app_from_router { + ... +} + +---- + +benefits of OX + +---- + +reuse ++no wrapper classes required + +---- perl,i4 + +package App; +use OX; + +has model => (is => 'ro', isa => 'KiokuX::Model'); +has view => (is => 'ro', isa => 'Template'); + +... + +---- perl,i4 + +package App; +use OX; + +has dsn => (is => 'ro', isa => 'Str', default => 'dbi:sqlite:app.sqlite'); +has root => (is => 'ro', isa => 'Str', default => 'root/templates'); + +has model => ( + is => 'ro', + isa => 'KiokuX::Model', + dependencies => ['dsn'], +); +has view => ( + is => 'ro', + isa => 'Template', + dependencies => { INCLUDE_PATH => 'root' }, +); + +... + +---- + +application classes are decoupled, and can be used independently + +---- perl,i4 + +App->new->model + +---- + +get the model object exactly as it would be initialized within the app ++except without initializing the app ++very useful for standalone scripts + +---- + +App->new(dsn => 'dbi:SQLite::memory:')->to_app + +---- + +override specific bits of the application at initialization time ++makes testing very easy ++simple way to fit in mock objects, or adjust configuration for tests + +---- + +the entire structure is just building on existing technology ++applications can use roles and inheritance ++middleware just works ++components are just normal classes, can be built however you want + +---- + +TODO + +---- + +nested applications need work ++in particular, how can services be shared? + +---- + +bread::board subcontainers ++need a syntax for this + +---- + +more extensible routebuilders ++want a way to let the controller object control the dispatching + +---- + +cleaner underlying foundation ++more ways to customize the router ++more ways to customize the container + +---- center + +Any questions? + +http://github.com/stevan/OX/ diff --git a/themes/tozt/LICENSE b/themes/tozt/LICENSE index 624b3f3..0098881 100644 --- a/themes/tozt/LICENSE +++ b/themes/tozt/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018 YOUR_NAME_HERE +Copyright (c) 2017 Yihui Xie, Jesse Luehrs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/themes/tozt/README b/themes/tozt/README new file mode 100644 index 0000000..b064e13 --- /dev/null +++ b/themes/tozt/README @@ -0,0 +1 @@ +based on https://github.com/yihui/hugo-xmin diff --git a/themes/tozt/archetypes/default.md b/themes/tozt/archetypes/default.md deleted file mode 100644 index ac36e06..0000000 --- a/themes/tozt/archetypes/default.md +++ /dev/null @@ -1,2 +0,0 @@ -+++ -+++ diff --git a/themes/tozt/layouts/404.html b/themes/tozt/layouts/404.html index e69de29..c2e4e40 100644 --- a/themes/tozt/layouts/404.html +++ b/themes/tozt/layouts/404.html @@ -0,0 +1,5 @@ +{{ partial "header.html" . }} + +404 NOT FOUND + +{{ partial "footer.html" . }} diff --git a/themes/tozt/layouts/_default/baseof.html b/themes/tozt/layouts/_default/baseof.html deleted file mode 100644 index 5f8e2ec..0000000 --- a/themes/tozt/layouts/_default/baseof.html +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE html> -<html> - {{- partial "head.html" . -}} - <body> - {{- partial "header.html" . -}} - <div id="content"> - {{- block "main" . }}{{- end }} - </div> - {{- partial "footer.html" . -}} - </body> -</html> diff --git a/themes/tozt/layouts/_default/list.html b/themes/tozt/layouts/_default/list.html deleted file mode 100644 index e69de29..0000000 --- a/themes/tozt/layouts/_default/list.html +++ /dev/null diff --git a/themes/tozt/layouts/_default/single.html b/themes/tozt/layouts/_default/single.html index e69de29..9e2cd9a 100644 --- a/themes/tozt/layouts/_default/single.html +++ b/themes/tozt/layouts/_default/single.html @@ -0,0 +1,9 @@ +{{ partial "header.html" . }} + +<h2>{{ .Title }}</h2> + +<main> +{{ .Content }} +</main> + +{{ partial "footer.html" . }} diff --git a/themes/tozt/layouts/blog/list.html b/themes/tozt/layouts/blog/list.html new file mode 100644 index 0000000..9483571 --- /dev/null +++ b/themes/tozt/layouts/blog/list.html @@ -0,0 +1,14 @@ +{{ partial "header.html" . }} + +{{ .Content }} + +<ul> + {{ range (where .Data.Pages "Section" "!=" "") }} + <li> + <span class="date">{{ .Date.Format "2006/01/02" }}</span> + <a href="{{ .URL }}">{{ .Title | markdownify }}</a> + </li> + {{ end }} +</ul> + +{{ partial "footer.html" . }} diff --git a/themes/tozt/layouts/blog/single.html b/themes/tozt/layouts/blog/single.html new file mode 100644 index 0000000..762678e --- /dev/null +++ b/themes/tozt/layouts/blog/single.html @@ -0,0 +1,10 @@ +{{ partial "header.html" . }} + +<h2>{{ .Title }}</h2> +<h3>{{ .Date.Format "Mon, Jan 2, 2006" }}</h3> + +<main> +{{ .Content }} +</main> + +{{ partial "footer.html" . }} diff --git a/themes/tozt/layouts/index.html b/themes/tozt/layouts/index.html index e69de29..5ea7912 100644 --- a/themes/tozt/layouts/index.html +++ b/themes/tozt/layouts/index.html @@ -0,0 +1,7 @@ +{{ partial "header.html" . }} + +<main> +{{ .Content }} +</main> + +{{ partial "footer.html" . }} diff --git a/themes/tozt/layouts/partials/footer.html b/themes/tozt/layouts/partials/footer.html index e69de29..6a2722e 100644 --- a/themes/tozt/layouts/partials/footer.html +++ b/themes/tozt/layouts/partials/footer.html @@ -0,0 +1,7 @@ + <footer> + <div class="lastmod"> + Last modified {{ .Lastmod }} + </div> + </footer> + </body> +</html> diff --git a/themes/tozt/layouts/partials/head.html b/themes/tozt/layouts/partials/head.html deleted file mode 100644 index e69de29..0000000 --- a/themes/tozt/layouts/partials/head.html +++ /dev/null diff --git a/themes/tozt/layouts/partials/header.html b/themes/tozt/layouts/partials/header.html index e69de29..11a00f3 100644 --- a/themes/tozt/layouts/partials/header.html +++ b/themes/tozt/layouts/partials/header.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html lang="{{ .Site.LanguageCode }}"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>{{ .Title }} | {{ .Site.Title }}</title> + <link rel="stylesheet" href="{{ "/css/style.css" | relURL }}" /> + <link rel="stylesheet" href="{{ "/css/fonts.css" | relURL }}" /> + </head> + + <body> + <h1><span class="title">{{ .Site.Title | markdownify }}</span></h1> + <nav> + <ul class="menu"> + {{ range .Site.Menus.main }} + <li><a href="{{ .URL | relURL }}">{{ .Name }}</a></li> + {{ end }} + </ul> + <hr/> + </nav> diff --git a/themes/tozt/static/css/fonts.css b/themes/tozt/static/css/fonts.css new file mode 100644 index 0000000..8ffcecd --- /dev/null +++ b/themes/tozt/static/css/fonts.css @@ -0,0 +1,7 @@ +body { + font-family: Optima, Candara, Calibri, Arial, sans-serif; +} +code { + font-family: "Lucida Console", Monaco, monospace; + font-size: 85%; +} diff --git a/themes/tozt/static/css/style.css b/themes/tozt/static/css/style.css new file mode 100644 index 0000000..5fc24c6 --- /dev/null +++ b/themes/tozt/static/css/style.css @@ -0,0 +1,56 @@ +body { + max-width: 800px; + margin: auto; + padding: 1em; + line-height: 1.5em; +} + +/* header and footer areas */ +.menu { padding: 0; } +.menu li { display: inline-block; } +.article-meta, .menu a { + text-decoration: none; + background: #eee; + padding: 5px; + border-radius: 5px; +} +.menu, .article-meta, footer { text-align: center; } +.title { font-size: 1.1em; } +footer a { text-decoration: none; } +hr { + border-style: dashed; + color: #ddd; +} + +/* code */ +pre { + border: 1px solid #ddd; + box-shadow: 5px 5px 5px #eee; + padding: 1em; + overflow-x: auto; +} +code { background: #f9f9f9; } +pre code { background: none; } + +/* misc elements */ +img, iframe, video { max-width: 100%; } +main { hyphens: auto; } +blockquote { + background: #f9f9f9; + border-left: 5px solid #ccc; + padding: 3px 1em 3px; +} + +table { + margin: auto; + border-top: 1px solid #666; + border-bottom: 1px solid #666; +} +table thead th { border-bottom: 1px solid #ddd; } +th, td { padding: 5px; } +thead, tfoot, tr:nth-child(even) { background: #eee } + +.lastmod { + font-size: smaller; + font-style: italic; +} diff --git a/themes/tozt/theme.toml b/themes/tozt/theme.toml index fcd60cf..8733afd 100644 --- a/themes/tozt/theme.toml +++ b/themes/tozt/theme.toml @@ -1,21 +1,12 @@ -# theme.toml template for a Hugo theme -# See https://github.com/gohugoio/hugoThemes#themetoml for an example - -name = "Tozt" +name = "XMin" license = "MIT" -licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE" -description = "" -homepage = "http://example.com/" -tags = [] -features = [] -min_version = "0.41" +licenselink = "https://github.com/yihui/hugo-xmin/blob/master/LICENSE.md" +description = "eXtremely Minimal Hugo theme: about 150 lines of code in total, including HTML and CSS" +homepage = "https://xmin.yihui.name" +tags = ["minimal", "blog", "personal", "clean", "simple", "starter", "minimalist"] +features = ["blog"] +min_version = "0.18" [author] - name = "" - homepage = "" - -# If porting an existing theme -[original] - name = "" - homepage = "" - repo = "" + name = "Yihui Xie" + homepage = "https://yihui.name" |