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

How to make DSL

May 11, 2015

Download

Technology

Yukio Goto

This is slide how to make DSL using Ruby.
You can understand making your own DSL.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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