84
DSL Powered by Rabbit 2.1.2 DSL Yukio Goto sg.rb 2014/04/29

How to make DSL

Embed Size (px)

DESCRIPTION

This is slide how to make DSL using Ruby. You can understand making your own DSL.

Citation preview

Page 1: How to make DSL

DSL Powered by Rabbit 2.1.2

DSL

Yukio Gotosg.rb

2014/04/29

Page 2: How to make DSL

DSL Powered by Rabbit 2.1.2

Who am I ?

Yukio Gotofavorite

Ruby, emacs, zsh, tennis✓✓

workRakuten Asia Pte. Ltd.✓As senior application engineer✓

Page 3: How to make DSL

DSL Powered by Rabbit 2.1.2

IDs

github

https://github.com/byplayer/

twitter

@byplayer

Page 4: How to make DSL

DSL Powered by Rabbit 2.1.2

Today's target

use DSL -*-*-*-*-*-*- making DSL

Page 5: How to make DSL

DSL Powered by Rabbit 2.1.2

DSL

What is DSL ?

Page 6: How to make DSL

DSL Powered by Rabbit 2.1.2

DSL

DSL =Domain Specific

Language

Page 7: How to make DSL

DSL Powered by Rabbit 2.1.2

external DSL

SQL✓

SELECT id, user_name FROM users

Page 8: How to make DSL

DSL Powered by Rabbit 2.1.2

external DSL

configuration files✓

http { passenger_root /usr/local/rvm/gems/ruby-2.1.0/gems/passenger-4.0.29; passenger_ruby /usr/local/rvm/wrappers/ruby-2.1.0/ruby;

include mime.types; default_type application/octet-stream;

# ...}

Page 9: How to make DSL

DSL Powered by Rabbit 2.1.2

internal DSL

Rails✓

class User < ActiveRecord::Base validates :name, presence: trueend

Page 10: How to make DSL

DSL Powered by Rabbit 2.1.2

BTW

By the way

Page 11: How to make DSL

DSL Powered by Rabbit 2.1.2

Did you make DSL ?

Did you make DSL ?

Page 12: How to make DSL

DSL Powered by Rabbit 2.1.2

use only ?

Do you think

you can only use DSL?

Page 13: How to make DSL

DSL Powered by Rabbit 2.1.2

No

NO !!!

Page 14: How to make DSL

DSL Powered by Rabbit 2.1.2

You

You

Page 15: How to make DSL

DSL Powered by Rabbit 2.1.2

can

can

Page 16: How to make DSL

DSL Powered by Rabbit 2.1.2

make

make

Page 17: How to make DSL

DSL Powered by Rabbit 2.1.2

your own DSL

your own DSL

Page 18: How to make DSL

DSL Powered by Rabbit 2.1.2

AND

AND

Page 19: How to make DSL

DSL Powered by Rabbit 2.1.2

Ruby

Rubyis

Page 20: How to make DSL

DSL Powered by Rabbit 2.1.2

easiest language

one of the most

easiest language

Page 21: How to make DSL

DSL Powered by Rabbit 2.1.2

making DSL

making DSL

Page 22: How to make DSL

DSL Powered by Rabbit 2.1.2

How to make DSL

How to make DSL

Page 23: How to make DSL

DSL Powered by Rabbit 2.1.2

before that

Before that

Page 24: How to make DSL

DSL Powered by Rabbit 2.1.2

Benefit of making DSL

DSL makes your Applicationeasy to write✓easy to read✓easy to use✓

Page 25: How to make DSL

DSL Powered by Rabbit 2.1.2

theme

Configuration file using DSL

Page 26: How to make DSL

DSL Powered by Rabbit 2.1.2

config version 1

# singapore-ruby-group.confmeetup do |conf| conf.group = 'Singapore-Ruby-Group' conf.organizer = 'Winston Teo' conf.sponsors = ['Engine Yard', 'Silicon Straits', 'Plug-In@Blk71']end

Page 27: How to make DSL

DSL Powered by Rabbit 2.1.2

how to use

mt = Meetup.load('singapore-ruby-group.conf')

puts mt.group# => Singapore-Ruby-Group

puts mt.organizer# => Winston Teo

puts mt.sponsors.join(', ')# => Engine Yard, Silicon Straits, Plug-In@Blk71

Page 28: How to make DSL

DSL Powered by Rabbit 2.1.2

implementation

# Sample class to load configurationclass Meetup attr_accessor :group, :organizer, :sponsors

def self.load(path) fail "config file not found: #{path}" unless File.exist?(path)

mt = Meetup.new File.open(path, 'r') do |file| mt.instance_eval(File.read(path), path) end

mt end

private

def meetup yield self endend

Page 29: How to make DSL

DSL Powered by Rabbit 2.1.2

key point

def self.load # ... File.open(path, 'r') do |file| mt.instance_eval(File.read(path), path) end # ...end

def meetup yield selfend

Page 30: How to make DSL

DSL Powered by Rabbit 2.1.2

first point

pass string to 'instance_eval'

def self.load # ... File.open(path, 'r') do |file| mt.instance_eval(File.read(path), path) end # ...end

Page 31: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

"instance_eval"

Page 32: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

interpretes String

Page 33: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

as Ruby code

Page 34: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

using Object context

Page 35: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

In this case,

Page 36: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

configuration file is

Page 37: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

interpreted as

Page 38: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval

Meetup class source code

Page 39: How to make DSL

DSL Powered by Rabbit 2.1.2

expand instance_eval virtually

def self.load # File.open(path, 'r') do |file| # mt.instance_eval(File.read(path), path) # end meetup do |conf| conf.group = 'Singapore-Ruby-Group' conf.organizer = 'Winston Teo' conf.sponsors = ['Engine Yard', 'Silicon Straits', 'Plug-In@Blk71'] endend

Page 40: How to make DSL

DSL Powered by Rabbit 2.1.2

easy

quite easy

Page 41: How to make DSL

DSL Powered by Rabbit 2.1.2

but

BUT

Page 42: How to make DSL

DSL Powered by Rabbit 2.1.2

Typing config

Typing 'conf.'

Page 43: How to make DSL

DSL Powered by Rabbit 2.1.2

is is

is not

Page 44: How to make DSL

DSL Powered by Rabbit 2.1.2

sexy

sexy

Page 45: How to make DSL

DSL Powered by Rabbit 2.1.2

Is it sexy ?

meetup do |conf| conf.group = 'Singapore-Ruby-Group' conf.organizer = 'Winston Teo' conf.sponsors = ['Engine Yard', 'Silicon Straits', 'Plug-In@Blk71']end

Page 46: How to make DSL

DSL Powered by Rabbit 2.1.2

ideal configuration

# singapore-ruby-group.confmeetup { group 'Singapore-Ruby-Group' organizer 'Winston Teo' sponsors ['Engine Yard', 'Silicon Straits', 'Plug-In@Blk71']}

Page 47: How to make DSL

DSL Powered by Rabbit 2.1.2

readable

readable✓

DRY✓

Page 48: How to make DSL

DSL Powered by Rabbit 2.1.2

Let's use

Let's use

Page 49: How to make DSL

DSL Powered by Rabbit 2.1.2

Ruby's black magic

Ruby's black magic

Page 50: How to make DSL

DSL Powered by Rabbit 2.1.2

parsing

parsing it

Page 51: How to make DSL

DSL Powered by Rabbit 2.1.2

load

class Meetup attr_accessor :group, :organizer, :sponsors

def self.load(path) mt = new File.open(path, 'r') do |file| loader = MeetupLoader.new(mt) loader.instance_eval(file.read, path) end

mt endend

Page 52: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class

make support class

MeetupLoader

Page 53: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class

define setter method

Page 54: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class

not use '='

Page 55: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class

and

Page 56: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class

load function(meetup) only

Page 57: How to make DSL

DSL Powered by Rabbit 2.1.2

make support class (setter)

class MeetupLoader def initialize(mt) @meetup = mt end # ... def group(g) @meetup.group = g end

def organizer(o) @meetup.organizer = o end # ...end

Page 58: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval again

class MeetupLoader # ... def meetup(&block) instance_eval(&block) end # ...end

Page 59: How to make DSL

DSL Powered by Rabbit 2.1.2

The point of black magic

instance_eval again

Page 60: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval for block

instance_eval with block

Page 61: How to make DSL

DSL Powered by Rabbit 2.1.2

changes

changes

Page 62: How to make DSL

DSL Powered by Rabbit 2.1.2

default receiver

default receiver

Page 63: How to make DSL

DSL Powered by Rabbit 2.1.2

in the block

in the block

Page 64: How to make DSL

DSL Powered by Rabbit 2.1.2

original code

class Meetup attr_accessor :group, :organizer, :sponsors

def self.load(path) mt = new File.open(path, 'r') do |file| loader = MeetupLoader.new(mt) loader.instance_eval(file.read, path) end

mt endend

Page 65: How to make DSL

DSL Powered by Rabbit 2.1.2

expand instance_eval virtually 1

def self.load(path) mt = new File.open(path, 'r') do |file| loader = MeetupLoader.new(mt) # loader.instance_eval(file.read, path) loader.meetup { group 'Singapore-Ruby-Group' organizer 'Winston Teo' # ... } end #...

Page 66: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval with block

class MeetupLoader # ... def meetup(&block) instance_eval(&block) end # ...end

Page 67: How to make DSL

DSL Powered by Rabbit 2.1.2

expand instance_eval virtually 2

def meetup(&block) # instance_eval(&block) #{ self.group 'Singapore-Ruby-Group' self.organizer 'Winston Teo' # ... # }end

Page 68: How to make DSL

DSL Powered by Rabbit 2.1.2

The trick

The trick

Page 69: How to make DSL

DSL Powered by Rabbit 2.1.2

of

of

Page 70: How to make DSL

DSL Powered by Rabbit 2.1.2

Ruby's black magic

Ruby's black magic

Page 71: How to make DSL

DSL Powered by Rabbit 2.1.2

is

is

Page 72: How to make DSL

DSL Powered by Rabbit 2.1.2

instance_eval with block

instance_eval with block

Page 73: How to make DSL

DSL Powered by Rabbit 2.1.2

expand instance_eval virtually 2

def meetup(&block) # instance_eval(&block) #{ self.group 'Singapore-Ruby-Group' self.organizer 'Winston Teo' # ... # }end

Page 74: How to make DSL

DSL Powered by Rabbit 2.1.2

Today

Today,

Page 75: How to make DSL

DSL Powered by Rabbit 2.1.2

I

I

Page 76: How to make DSL

DSL Powered by Rabbit 2.1.2

don't

don't

Page 77: How to make DSL

DSL Powered by Rabbit 2.1.2

talk about

talk about

Page 78: How to make DSL

DSL Powered by Rabbit 2.1.2

caution points

caution points

Page 79: How to make DSL

DSL Powered by Rabbit 2.1.2

caution points

security✓

handle method_missing✓handle syntax error✓

Page 80: How to make DSL

DSL Powered by Rabbit 2.1.2

source code

https://github.com/byplayer/meetup_config✓https://github.com/byplayer/meetup_config_ex

Page 81: How to make DSL

DSL Powered by Rabbit 2.1.2

take a way

You can make DSL✓

instance_eval is interesting✓

Page 82: How to make DSL

DSL Powered by Rabbit 2.1.2

Hiring

Rakuten Asia Pte. Ltd. wants to hire

Server side Application Engineer (Ruby, java)

iOS, Android Application Engineer

Page 83: How to make DSL

DSL Powered by Rabbit 2.1.2

Any question ?

Any question ?

Page 84: How to make DSL

DSL Powered by Rabbit 2.1.2

Thank you

Thank youfor listening