Slide 1

Slide 1 text

@kkuchta ruby = "amazing"

Slide 2

Slide 2 text

@kkuchta ruby = "amazing"

Slide 3

Slide 3 text

@kkuchta Ruby Assignment x = 3

Slide 4

Slide 4 text

@kkuchta Ruby Assignment x = 3

Slide 5

Slide 5 text

@kkuchta Ruby Assignment 3 => x

Slide 6

Slide 6 text

@kkuchta Ruby Assignment 3 => x

Slide 7

Slide 7 text

@kkuchta Ruby Assignment 3 = x

Slide 8

Slide 8 text

Vertical Assignment In Ruby Kevin Kuchta He/Him Daybreak Health @kkuchta

Slide 9

Slide 9 text

@kkuchta Hello Operator x = 3 3 => x

Slide 10

Slide 10 text

@kkuchta Hello Operator 3 ? x x = 3 3 => x

Slide 11

Slide 11 text

@kkuchta 3 || x Hello Operator x = 3 3 => x

Slide 12

Slide 12 text

@kkuchta Hello Operator x = true || false

Slide 13

Slide 13 text

@kkuchta Hello Operator class Integer; def +(_); 3; end; end puts 1 + 1 # returns 3

Slide 14

Slide 14 text

@kkuchta Hello Operator 🌮

Slide 15

Slide 15 text

@kkuchta Hello Operator def 🌮🌮🌮 return "yum" end 🌮🌮🌮 => 👄 puts 👄 # "yum"

Slide 16

Slide 16 text

@kkuchta Hello Operator

Slide 17

Slide 17 text

@kkuchta Vertical Assignment Operator 3 ‖ x

Slide 18

Slide 18 text

@kkuchta Vertical Assignment Operator Seems like a valid expression... 3 ‖ x

Slide 19

Slide 19 text

@kkuchta Vertical Assignment Operator NameError: unde f ined local variable or method `‖' for main:Object Seems like a valid expression... 3 ‖ x

Slide 20

Slide 20 text

@kkuchta Vertical Assignment Operator Object.define_method(:‖) {|*_|} 3 ‖ x

Slide 21

Slide 21 text

@kkuchta Vequals Operator Object.define_method(:‖) {|*_|} 3 ‖ x

Slide 22

Slide 22 text

@kkuchta NameError: unde f ined local variable or method `x' for main:Object Vequals Operator Object.define_method(:‖) {|*_|} 3 ‖ x

Slide 23

Slide 23 text

@kkuchta Ruby Assignment x = 3

Slide 24

Slide 24 text

@kkuchta Ruby Assignment 3 => x

Slide 25

Slide 25 text

@kkuchta Ruby Assignment Object.define_method(:‖) {|*_|} 3 ‖ x

Slide 26

Slide 26 text

@kkuchta TracePoint

Slide 27

Slide 27 text

@kkuchta TracePoint tracepoint = TracePoint.new(:raise) do |tp| # Do cool thing here end tracepoint.enable

Slide 28

Slide 28 text

@kkuchta TracePoint tracepoint = TracePoint.new(:raise) do |tp| # Do cool thing here end tracepoint.enable raise "zomg" raise "wtf" raise "bbq"

Slide 29

Slide 29 text

@kkuchta tracepoint = TracePoint.new(:call) do |tp| # Do cool thing here end tracepoint.enable TracePoint

Slide 30

Slide 30 text

@kkuchta tracepoint = TracePoint.new(:call) do |tp| # Do cool thing here end tracepoint.enable TracePoint 123.to_i foo.bar() [1,2,3].last

Slide 31

Slide 31 text

@kkuchta TracePoint on every line # run this block on every subsequent line... tracepoint = TracePoint.new(:line) do |tp| puts "tracing line #{tp.lineno} in file #{tp.path}" end # ...starting now! tracepoint.enable

Slide 32

Slide 32 text

@kkuchta TracePoint on every line # run this block on every subsequent line... tracepoint = TracePoint.new(:line) do |tp| puts "tracing line #{tp.lineno} in file #{tp.path}" end # ...starting now! tracepoint.enable x = 3 # prints "tracing line 6 in file ./tmp.rb" y = x + 1 # prints "tracing line 7 in file ./tmp.rb" z = x / y # prints "tracing line 9 in file ./tmp.rb"

Slide 33

Slide 33 text

@kkuchta Binding tracepoint = TracePoint.new(:call) do |tp| tp.binding end tracepoint.enable

Slide 34

Slide 34 text

@kkuchta Binding binding_at_this_point = binding()

Slide 35

Slide 35 text

@kkuchta Binding def foo x = 3 return binding() end

Slide 36

Slide 36 text

@kkuchta Binding def foo x = 3 return binding() end puts x # error: no local variable x

Slide 37

Slide 37 text

@kkuchta Binding def foo x = 3 return binding() end puts x # error: no local variable x foos_binding = foo

Slide 38

Slide 38 text

@kkuchta Binding def foo x = 3 return binding() end puts x # error: no local variable x foos_binding = foo puts foos_binding.local_variable_get(:x) # 3

Slide 39

Slide 39 text

@kkuchta TracePoint 3 ‖ x

Slide 40

Slide 40 text

@kkuchta TracePoint 3 ‖ x

Slide 41

Slide 41 text

@kkuchta Binding TracePoint.new(:line) do |tp| line = tp.line if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x

Slide 42

Slide 42 text

@kkuchta Binding TracePoint.new(:line) do |tp| line = tp.line if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x

Slide 43

Slide 43 text

@kkuchta TracePoint

Slide 44

Slide 44 text

@kkuchta TracePoint tp.lineno # 123

Slide 45

Slide 45 text

@kkuchta TracePoint tp.lineno # 123 tp.path # ./whatever.rb

Slide 46

Slide 46 text

@kkuchta TracePoint tp.lineno # 123 tp.path # ./whatever.rb scruples

Slide 47

Slide 47 text

@kkuchta TracePoint TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] puts line; end.enable # prints out "x = 4": x = 4

Slide 48

Slide 48 text

@kkuchta TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x Binding

Slide 49

Slide 49 text

@kkuchta TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x Binding

Slide 50

Slide 50 text

@kkuchta TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include? "x" tp.binding.local_variable_set(:x, "🐥") end end.enable puts x Binding

Slide 51

Slide 51 text

@kkuchta Binding x = 3 my_binding = binding() my_binding.local_variable_set(:x, 4) puts x # 4

Slide 52

Slide 52 text

@kkuchta Binding x = 3 my_binding = binding() my_binding.local_variable_set(:x, 4) puts x # 4 my_binding.local_variable_set(:y, 5) puts y # error, y is undefined!

Slide 53

Slide 53 text

@kkuchta Binding

Slide 54

Slide 54 text

@kkuchta Binding my_binding = binding() my_binding.eval("def x(*args) = 3") puts x # 3

Slide 55

Slide 55 text

@kkuchta Binding my_binding = binding() my_binding.eval("def x(*args) = 3") puts x # 3 x = 4 puts x # 4

Slide 56

Slide 56 text

@kkuchta Binding line = tp.line line = File.readlines(tp.path)[tp.lineno - 1] tp.binding.local_variable_set(:x, "3") my_binding.eval("def x(*args) = 3")

Slide 57

Slide 57 text

@kkuchta Success! TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include?("x") tp.binding.eval("def x(*args) = 3") end end.enable puts x # 3 TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include?("x") tp.binding.eval("def x(*args) = 3") end end.enable puts x # 3

Slide 58

Slide 58 text

@kkuchta Success! TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] if line.include?("x") tp.binding.eval("def x(*args) = 3") end end.enable puts x # 3

Slide 59

Slide 59 text

@kkuchta Success! TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] line.split(' ').each do |token| next if token == "puts" tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x puts y puts z TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] line.split(' ').each do |token| next if token == "puts" tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x puts y puts z

Slide 60

Slide 60 text

@kkuchta Success! TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] line.split(' ').each do |token| next if token == "puts" tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x puts y puts z

Slide 61

Slide 61 text

@kkuchta Brittle as heck > line = "puts x # hi there!" > line.split(' ') ["puts", "x", "#", "hi", "there!"]

Slide 62

Slide 62 text

@kkuchta Success! x = y * 3 + z(7) # foo

Slide 63

Slide 63 text

@kkuchta Success! Identi f ier Operator Literal Comment x = y * 3 + z(7) # foo

Slide 64

Slide 64 text

@kkuchta Ripper

Slide 65

Slide 65 text

@kkuchta Ripper require 'ripper' pp Ripper.sexp(" x = 3 y = x + 1 ")

Slide 66

Slide 66 text

@kkuchta Ripper require 'ripper' pp Ripper.sexp(" x = 3 y = x + 1 ") [:program, [[:assign, [:var_field, [:@ident, "x", [2, 2]]], [:@int, "3", [2, 6]]], [:assign, [:var_field, [:@ident, "y", [3, 2]]], [:binary, [:var_ref, [:@ident, "x", [3, 6]]], :+, [:@int, "1", [3, 10]]]]]]

Slide 67

Slide 67 text

@kkuchta Sexp pp Ripper.sexp('def foo;') # nil pp Ripper.sexp('x = (') # nil pp Ripper.sexp('class bar') # nil

Slide 68

Slide 68 text

@kkuchta Sexp "foo = bar + baz()" ["foo", " ", "=", " ", "bar", " ", "+", " ", "baz", "(", ")"] [[:assign, [:var_field, [:@ident, "foo", [1, 0]]], [:binary, [:vcall, [:@ident, "bar", [1, 6]]], :+, [:method_add_arg, [:fcall, [:@ident, "baz", [1, 12]]], [:arg_paren, nil]]]]]

Slide 69

Slide 69 text

@kkuchta Lexing Ripper.lex("foo = bar + baz()") .map{|_,_,token,_| token} => ["foo", " ", "=", " ", "bar", " ", "+", " ", "baz", "(", ")"]

Slide 70

Slide 70 text

@kkuchta Split by spaces TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] line.split(' ').each do |token| next if token == "puts" tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x

Slide 71

Slide 71 text

@kkuchta Lexing TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, __, token, ___| next if token == "puts" || token == " " tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, __, token, ___| next if token == "puts" || token == " " tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, __, token, ___| next if token == "puts" || token == " " tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x

Slide 72

Slide 72 text

@kkuchta Lexing TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, __, token, ___| next if token == "puts" || token == " " tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, __, token, ___| next if token == "puts" || token == " " tp.binding.eval("def #{token}(*args) = 3") end end.enable puts x

Slide 73

Slide 73 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 74

Slide 74 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 75

Slide 75 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 76

Slide 76 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 77

Slide 77 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 78

Slide 78 text

@kkuchta > Ripper.lex("foo = bar + baz()") [ [[1, 0], :on_ident, "foo", CMDARG], [[1, 3], :on_sp, " ", CMDARG], [[1, 4], :on_op, "=", BEG], [[1, 5], :on_sp, " ", BEG], [[1, 6], :on_ident, "bar", ARG], [[1, 9], :on_sp, " ", ARG], [[1, 10], :on_op, "+", BEG], [[1, 11], :on_sp, " ", BEG], [[1, 12], :on_ident, "baz", ARG], [[1, 15], :on_lparen, "(", BEG|LABEL], [[1, 16], :on_rparen, ")", ENDFN] ] Lexing into tokens

Slide 79

Slide 79 text

@kkuchta Searching for identi f iers require 'ripper' TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, type, token, ___| if type == :on_ident tp.binding.eval("def #{token}(*args) = 3") end end end.enable puts x

Slide 80

Slide 80 text

@kkuchta Searching for identi f iers require 'ripper' TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, type, token, ___| if type == :on_ident next if tp.binding.receiver.respond_to?(token) || Kernel.respond_to?(token) tp.binding.eval("def #{token}(*args) = 3") end end end.enable puts x # 3 require 'ripper' TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, type, token, ___| if type == :on_ident next if tp.binding.receiver.respond_to?(token) || Kernel.respond_to?(token) tp.binding.eval("def #{token}(*args) = 3") end end end.enable puts x # 3

Slide 81

Slide 81 text

@kkuchta Searching for identi f iers require 'ripper' TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] tokens = Ripper.lex(line) tokens.each do |_, type, token, ___| if type == :on_ident next if tp.binding.receiver.respond_to?(token) || Kernel.respond_to?(token) tp.binding.eval("def #{token}(*args) = 3") end end end.enable puts x # 3

Slide 82

Slide 82 text

@kkuchta Putting it together Object.send(:define_method, :‖) {|*_|} TracePoint.new(:line) do |tp| # ... see previous slide ... end 7 ‖ x

Slide 83

Slide 83 text

@kkuchta High Level Approach 7 ‖ foo

Slide 84

Slide 84 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line

Slide 85

Slide 85 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line

Slide 86

Slide 86 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line

Slide 87

Slide 87 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖

Slide 88

Slide 88 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions

Slide 89

Slide 89 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions

Slide 90

Slide 90 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions 3. Stash the column and expression

Slide 91

Slide 91 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions 3. Stash the column and expression vequals_to_process = [ {col: 1, expression: "7"} ]

Slide 92

Slide 92 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions 3. Stash the column and expression 4. Store the value of the expression vequals_to_process = [ {col: 1, expression: "7"} ]

Slide 93

Slide 93 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions 3. Stash the column and expression 4. Store the value of the expression vequals_to_process = [ {col: 1, value: eval("7")} ]

Slide 94

Slide 94 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1. Lex this line and look for ‖ 2. Lex the line above for expressions 3. Stash the column and expression 4. Store the value of the expression vequals_to_process = [ {col: 1, value: 7} ]

Slide 95

Slide 95 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line vequals_to_process = [ {col: 1, value: 7} ]

Slide 96

Slide 96 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line vequals_to_process = [ {col: 1, value: 7} ]

Slide 97

Slide 97 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers vequals_to_process = [ {col: 1, value: 7} ]

Slide 98

Slide 98 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers Identi f ier 'foo' spans from 0 to 2 vequals_to_process = [ {col: 1, value: 7} ]

Slide 99

Slide 99 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers 2.Is this identi f ier is below a ‖? Identi f ier 'foo' spans from 0 to 2 vequals_to_process = [ {col: 1, value: 7} ]

Slide 100

Slide 100 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers 2.Is this identi f ier is below a ‖? 3.Just-in-time de f ine that identi f ier to equal that value Identi f ier 'foo' spans from 0 to 2 vequals_to_process = [ {col: 1, value: 7} ]

Slide 101

Slide 101 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers 2.Is this identi f ier is below a ‖? 3.Just-in-time de f ine that identi f ier to equal that value Identi f ier 'foo' spans from 0 to 2 vequals_to_process = [ {col: 1, value: 7} ] def #{identifier}(*args) = value

Slide 102

Slide 102 text

@kkuchta High Level Approach 0 1 2 7 ‖ f o o Column Line 1.Lex this line for identi f iers 2.Is this identi f ier is below a ‖? 3.Just-in-time de f ine that identi f ier to equal that value Identi f ier 'foo' spans from 0 to 2 vequals_to_process = [ {col: 1, value: 7} ] def foo(*args) = 7

Slide 103

Slide 103 text

@kkuchta High Level Approach 1. Look for vequals to process next line 2. Look for identi f iers that line up with vequals from the previous line

Slide 104

Slide 104 text

@kkuchta Low Level Approach require 'ripper' class Vequals def enable @vequals_by_line = {} trace = TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] check_for_vequals(line, tp) process_any_vequals_from_previous_line(line, tp) end Object.define_method(:‖) {|*_|} trace.enable end def self.enable() Vequals.new.enable end def check_for_vequals(line, tp) @vequals_by_line[tp.lineno] = [] column = 0

Slide 105

Slide 105 text

@kkuchta Low Level Approach def self.enable() Vequals.new.enable end def check_for_vequals(line, tp) @vequals_by_line[tp.lineno] = [] column = 0 lexed = Ripper.lex(line) lexed.each do |_positions, type, token, state| if type == :on_ident && token == "‖" exp_above = get_exp(tp.path, tp.lineno - 1, column) eval_result = tp.binding.eval(exp_above) @vequals_by_line[tp.lineno] << { value_to_assign: eval_result, column: column } end column += token.length end end def process_any_vequals_from_previous_line(line, tp) return unless vequals_to_process = @vequals_by_line[tp.lineno-1]

Slide 106

Slide 106 text

@kkuchta Low Level Approach end column += token.length end end def process_any_vequals_from_previous_line(line, tp) return unless vequals_to_process = @vequals_by_line[tp.lineno-1] lexed = Ripper.lex(line) column = 0 lexed.each do |_positions, type, token, state| if type == :on_ident matching_vequals_entry = vequals_to_process.find do |vequals_entry| (column..(column + token.length)).include?(vequals_entry[:column]) end if matching_vequals_entry value_to_assign = matching_vequals_entry[:value_to_assign] if tp.binding.local_variable_defined?(token.to_sym) tp.binding.local_variable_set(token.to_sym, value_to_assign) else value_as_literal = literalize(value_to_assign) assignment_code = "def #{token}(*args) = #{value_as_literal}" tp.binding.eval(assignment_code) end end end column += token.length

Slide 107

Slide 107 text

@kkuchta Low Level Approach

Slide 108

Slide 108 text

@kkuchta Low Level Approach require 'ripper' class Vequals def enable @vequals_by_line = {} trace = TracePoint.new(:line) do |tp| line = File.readlines(tp.path)[tp.lineno - 1] check_for_vequals(line, tp) process_any_vequals_from_previous_line(line, tp) end Object.define_method(:‖) {|*_|} trace.enable end def self.enable() Vequals.new.enable end def check_for_vequals(line, tp) @vequals_by_line[tp.lineno] = [] column = 0 lexed = Ripper.lex(line) lexed.each do |_positions, type, token, state| if type == :on_ident && token == "‖" exp_above = get_exp(tp.path, tp.lineno - 1, column) eval_result = tp.binding.eval(exp_above) @vequals_by_line[tp.lineno] << { value_to_assign: eval_result, column: column } end column += token.length end end def process_any_vequals_from_previous_line(line, tp) return unless vequals_to_process = @vequals_by_line[tp.lineno-1] lexed = Ripper.lex(line) column = 0 lexed.each do |_positions, type, token, state| if type == :on_ident matching_vequals_entry = vequals_to_process.find do | vequals_entry| (column..(column + token.length)).include? (vequals_entry[:column]) end if matching_vequals_entry value_to_assign = matching_vequals_entry[:value_to_assign] if tp.binding.local_variable_defined?(token.to_sym) tp.binding.local_variable_set(token.to_sym, value_to_assign) else value_as_literal = literalize(value_to_assign) assignment_code = "def #{token}(*args) = #{value_as_literal}" tp.binding.eval(assignment_code) end end end column += token.length end end def get_exp(path, lineno, column) line = File.readlines(path)[lineno - 1] exp_ranges = get_exp_ranges(line) exp_range = exp_ranges.find do |exp_range| exp_range[1].include?(column) end exp_range[0] end def get_exp_ranges(line) lexed = Ripper.lex(line) column = 0 exp_ranges = [] lexed.each do |_positions, type, token, state| case type when :on_tstring_content exp_ranges << ["'" + token + "'", (column..(column + token.length))] when :on_ident exp_ranges << [token, (column..(column + token.length))] when :on_int exp_ranges << [token, (column..(column + token.length))] else # Skipping type end column += token.length end exp_ranges end def literalize(value) if value.is_a? String '"' + value + '"' else value end end end

Slide 109

Slide 109 text

@kkuchta It Works! Vequals.enable 7 ‖ foo puts foo # prints 7!

Slide 110

Slide 110 text

@kkuchta It Works! Vequals.enable [7, 123] ‖ ‖ foo bar puts foo # prints 7! puts bar # prints 123!

Slide 111

Slide 111 text

@kkuchta It Works! "yay" ‖ 123 foo ‖ bar puts foo # "yay" puts bar # 123

Slide 112

Slide 112 text

@kkuchta It Works! "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 113

Slide 113 text

@kkuchta It Works! 3 => fooooooobaaaaar ‖ ‖ ‖ ‖ ‖ d e f g h

Slide 114

Slide 114 text

@kkuchta It Works! [3, 4, 5] ‖ ‖ ‖ a = b <= 6 ‖ ‖ d => c ‖ ‖ x == e ‖ ‖ f = g = h => z

Slide 115

Slide 115 text

@kkuchta It Works! 1 ‖ x = x = x = x = x ‖ ‖ ‖ ‖ ‖ l = x = x = x = x ‖ ‖ ‖ ‖ ‖ l = x = x = x = l ‖ ‖ ‖ ‖ ‖ l = x = x = x = l ‖ ‖ i =___= i ‖ ‖ ‖ ‖ z z z z

Slide 116

Slide 116 text

@kkuchta Next Up x ⇑ 3

Slide 117

Slide 117 text

@kkuchta Next Up w => x ⇑ ‖ z = y

Slide 118

Slide 118 text

@kkuchta Exercises for the reader - Upward assignment - Diagonal assignment - Inward/outward assignment along the z axis - Forward and backwards in time assignment

Slide 119

Slide 119 text

@kkuchta Q&A "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 120

Slide 120 text

@kkuchta FAQ "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 121

Slide 121 text

@kkuchta FAQ Q: Who's responsible for this mess "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 122

Slide 122 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 123

Slide 123 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 124

Slide 124 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 125

Slide 125 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 126

Slide 126 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? A: Absolutely. "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 127

Slide 127 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? A: Absolutely.(Not you, Luke) "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 128

Slide 128 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? A: Absolutely. Q: I have a real question (Not you, Luke) "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 129

Slide 129 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? A: Absolutely. Q: I have a real question A: Right here! (Not you, Luke) "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 130

Slide 130 text

@kkuchta FAQ Q: Who's responsible for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/vequals Q: Should I use this in production? A: Absolutely. Q: I have a real question A: Right here! Q: Who in gods name hired you? (Not you, Luke) "foo" => bar ‖ aaaaa ‖ ‖ c = b ddd

Slide 131

Slide 131 text

@kkuchta DaybreakHealth.com [email protected] https://daybreak-health.breezy.hr/p/a27079cba61a-sr-backend-engineer

Slide 132

Slide 132 text

@kkuchta Thank You DaybreakHealth.com [email protected] https://daybreak-health.breezy.hr/p/a27079cba61a-sr-backend-engineer