Slide 1

Slide 1 text

Practical Meta Programming on Rails Application 3BJMTΞϓϦͰͷ ࣮༻తϝλϓϩάϥϛϯά MOROHASHI Kyosuke @2013-10-19 ߴ౓RubyΤϯδχΞҭ੒ߨ࠲

Slide 2

Slide 2 text

ॾڮګհ(@moro) Kyosuke MOROHASHI

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Agenda ✓ ϝλϓϩάϥϛϯάͱ͸ͳʹ͔ ✓ ϦϑϨΫγϣϯtoolbox ✓ ࣮༻ϝλϓϩάϥϛϯά ✓ ڞ௨ػೳͷநग़ ✓ ϥΠϒϥϦͷ࡞Γํ

Slide 6

Slide 6 text

ࠓ೔ͷΰʔϧ

Slide 7

Slide 7 text

✓ RubyͰ͸ϝλϓϩάϥϛϯά͸";ͭ ͏"ͩͱࢥ͑ΔΑ͏ʹͳΔ ✓ ϝλϓϩάϥϛϯά༻ͷRubyͷػೳʹͭ ͍ͯɺུ֓Λ͔ͭΉ ✓ ࣮ફతʹϝλϓϩάϥϛϯά͢Δͱ͖ͷ ஫ҙ఺ɾߟ͑ํΛཧղ͢Δ

Slide 8

Slide 8 text

http://www.amazon.co.jp/exec/obidos/ASIN/4048687158/morodiary05-22/ref=noism

Slide 9

Slide 9 text

✓ RubyͰ͸ϝλϓϩάϥϛϯά͸";ͭ ͏"ͩͱࢥ͑ΔΑ͏ʹͳΔ ✓ ϝλϓϩάϥϛϯά༻ͷRubyͷػೳʹͭ ͍ͯɺུ֓Λ͔ͭΉ ✓ ࣮ફతʹϝλϓϩάϥϛϯά͢Δͱ͖ͷ ஫ҙ఺ɾߟ͑ํΛཧղ͢Δ

Slide 10

Slide 10 text

ϝλϓϩάϥ ϛϯά ͱ͸ͳʹ͔

Slide 11

Slide 11 text

“ ϝλϓϩάϥϛϯάͱ͸ɺ ݴޠཁૉΛ࣮ߦ࣌ʹૢ࡞͢ ΔίʔυΛهड़͢Δ͜ͱ ʮϝλϓϩάϥϛϯάRubyʯ

Slide 12

Slide 12 text

Rubyͷݴޠཁૉ

Slide 13

Slide 13 text

✓ Ϋϥε ✓ Ϟδϡʔϧ ✓ ΦϒδΣΫτ ͱͦͷঢ়ଶΠϯελϯεม਺ ✓ ϝιου ✓ खଓ͖

Slide 14

Slide 14 text

class Book def title @title end def title=(title) @title = title end end

Slide 15

Slide 15 text

class Book def title @title end def title=(title) @title = title end end

Slide 16

Slide 16 text

ݴޠཁૉΛૢ࡞ͯ͠ Կ౓΋ग़͍ͯΔ 'title'͔Β͍Ζ ͍ΖͰ͖ͳ͍͔?

Slide 17

Slide 17 text

class Book attr_accessor :title end

Slide 18

Slide 18 text

def attr_accessor(name) define_method(name) do instance_variable_get("@#{name}") end define_method("#{name}=") do |val| instance_variable_set("@#{name}", val) end end

Slide 19

Slide 19 text

define_method(:title) do instance_variable_get("@title") end define_method("title=") do |val| instance_variable_set("@title", val) end

Slide 20

Slide 20 text

define_method(:title) do instance_variable_get("@title") end define_method("title=") do |val| instance_variable_set("@title", val) end ϝιουΛಈతʹ௥Ճ

Slide 21

Slide 21 text

define_method(:title) do instance_variable_get("@title") end define_method("title=") do |val| instance_variable_set("@title", val) end Πϯελϯεม਺Λ ม਺໊Λ࢖ͬͯૢ࡞

Slide 22

Slide 22 text

3VCZͰ͸ɺϝλϓ ϩάϥϛϯάͱͦ͏ Ͱͳ͍΋ͷͱʹ ໌֬ͳ۠ผ͸ͳ͍

Slide 23

Slide 23 text

·ͱΊϝλϓϩάϥϛϯάͱ͸ ✓ ݴޠཁૉΛૢ࡞͢Δ ✓ ࣮͸ಛผͳ΋ͷͰͳ͍ ✓ RubyͰ͸೔ৗతʹ΍͍ͬͯΔ

Slide 24

Slide 24 text

ϦϑϨΫγϣϯ toolbox

Slide 25

Slide 25 text

“ϦϑϨΫγϣϯ (re ection) ͱ ͸ɺϓϩάϥϜͷ࣮ߦաఔͰϓ ϩάϥϜࣗ਎ͷߏ଄ΛಡΈऔͬ ͨΓॻ͖׵͑ͨΓ͢Δٕज़ͷ͜ ͱͰ͋Δɻ http://ja.wikipedia.org/wiki/ϦϑϨΫγϣϯ _(৘ใ޻ֶ)

Slide 26

Slide 26 text

http://www.amazon.co.jp/exec/obidos/ASIN/4048687158/morodiary05-22/ref=noism

Slide 27

Slide 27 text

✓ RubyͰ͸ΫϥεͦΕࣗ਎΋ΦϒδΣΫ τͰ͋Δ ✓ ModuleΫϥεΛܧঝͨ͠ɺClassΫϥε ͷΦϒδΣΫτ ✓ ม਺ʹೖΕͨΓɺҾ਺ʹͨ͠ΓͰ͖Δ Class.is_a?(Object) #=> true

Slide 28

Slide 28 text

klasses = { 'array klass' => Array, 'hash klass' => Hash, } def class_name(klass) klass.name end klasses['array klass'].new #=> [] class_name(klasses['hash klass']) #=> "Hash"

Slide 29

Slide 29 text

✓ ΫϥεఆٛΛมߋ͢Δϝιου͕͋Δ ✓ include΍extend΍define_method ΋ModuleΫϥεͷϝιου Class.is_a?(Object) #=> true

Slide 30

Slide 30 text

✓ ॲཧͦͷ΋ͷΛΦϒδΣΫτͱ ͯ͠ѻ͑Δ ✓ Rubyͷେ͖ͳັྗͷҰͭ ϒϩοΫ(Proc)

Slide 31

Slide 31 text

# イテレータや処理の差し替え multiplier = ->(i) { i * 2 } square = ->(i) { i ** 2 } [1, 2, 3].map(&multiplier) [1, 2, 3].map(&square) # リソースの開閉 File.open(path, 'w') {|f| f.puts('content') } # 遅延評価 scope :fresh, -> { where('created_at > ?', 3.hour.ago) } ϒϩοΫ(Proc)

Slide 32

Slide 32 text

3VCZͷڭ͑ͯ͘Εͨ͜ͱ ౡాߒೋ [email protected] — You must unlearn what you have learned. ೥݄೔ ౔ ࡳຈ3VCZձٞ http://www.slideshare.net/snoozer05/20101204-youmustunlearnwhatyouhavelearned

Slide 33

Slide 33 text

✓ Ҿ਺Ͱࢦఆͨ͠ϝιουΛݺͼग़͢ ✓ ͭ·Γɺݺͼग़͢ϝιουΛϓϩάϥϜ తʹมߋͰ͖Δ Object#send

Slide 34

Slide 34 text

def up_or_down(condition) up_or_down = condition ? :upcase ? :downcase 'Ruby'.send(up_or_down) end up_or_down(true) # => 'RUBY' up_or_down(false) # => 'ruby' Object#send

Slide 35

Slide 35 text

✓ Ϟδϡʔϧ΍ΫϥεʹɺΠϯελϯεϝ ιουΛ௥Ճ͢Δϝιου ✓ defͷϦϑϨΫγϣϯ൛ ✓ ϝιουͷத਎ΛϒϩοΫͰॻ͘ ✓ ͦͷͨΊϒϩοΫ֎ͷม਺͕ݟ͑Δ define_method

Slide 36

Slide 36 text

class Foo foo = 'FOO' define_method(:foo1) do puts foo + '1' end def foo2 puts foo + '2' end end obj = Foo.new obj.foo1 #=> 'FOO1' obj.foo2 #=> NameError define_method

Slide 37

Slide 37 text

✓ จࣈྻͰॻ͔ΕͨRubyࣜ΍ϒϩοΫΛɺ Ϋϥε΍ΠϯελϯεͷίϯςΩετͰ ධՁ͢Δ class_eval/ instance_eval

Slide 38

Slide 38 text

✓ class_eval (module_eval)Λ࢖͏γʔϯ ✓ ClassΫϥεͷprivateϝιουΛݺΜͩΓɺ ✓ Classʹ͋ͱ͔ΒϝιουΛ௥Ճͨ͠Γ͢Δ ✓ instance_eval Λ࢖͏γʔϯ ✓ ΠϯελϯεͷΠϯελϯεม਺Λࢀর͢Δ ✓ privateϝιουΛݺͿ class_eval/ instance_eval

Slide 39

Slide 39 text

class Foo def initialize(message) @message = message end end Foo.class_eval %q[ def greet "#{@message} you!" end ] foo = Foo.new('hi') p foo.greet #=> 'hi you!' p foo.instance_eval { @message } #=> 'hi'

Slide 40

Slide 40 text

✓ Πϯελϯεม਺Λ໊લϕʔεͰऔಘ͠ ͨΓઃఆͨ͠ΓͰ͖Δ ✓ ͓ͳ͡Α͏ʹclass_varaible_set/ get΋͋Δ instance_variable_set/ instance_variable_get

Slide 41

Slide 41 text

class Foo def initialize(message) @message = message end end foo = Foo.new('hi') foo.instance_variable_get('@message') #=> 'hi'

Slide 42

Slide 42 text

✓ ଘࡏ͠ͳ͍ϝιουΛݺ͹Εͨ ࣌ʹݺ͹ΕΔϝιου ✓ ActiveRecordͷଐੑऔಘϝιο υͳͲʹ࢖ΘΕ͍ͯΔ method_missing

Slide 43

Slide 43 text

class Foo def method_missing(method, *args, &block) if method = :hi 'hello' else super end end end Foo.new.hi #=> 'hello' method_missing

Slide 44

Slide 44 text

✓ mixin΋Ϋϥε΍ϞδϡʔϧͷݴޠཁૉΛ ૢ࡞͍ͯ͠Δ ✓ include͸ͦͷΫϥεͷΠϯελϯεϝι ουΛ௥Ճ͢Δ ✓ extend͸ͦͷΦϒδΣΫτʹ(ಛҟ)ϝιο υΛ௥Ճ͢Δ include,extend

Slide 45

Slide 45 text

✓ Ϟδϡʔϧ͕include͞ΕͨΓextend͞Ε ͨΓ͢Δͱ࣮ߦ͞ΕΔϑοΫ ✓ ܧঝͷλΠϛϯάͰ࣮ߦ͞ΕΔinherited ϝιου΋͋Δ included, extended

Slide 46

Slide 46 text

module MyModule def self.included(base) "included by #{base}" end def self.extended(obj) "extended by #{obj}" end end class MyClass include MyModule # => "included by MyClass" end MyClass.new.extend(MyModule) # => "extended by #

Slide 47

Slide 47 text

✓ RailsʹΑΔincludeͷ֦ு ✓ ͦͷϞδϡʔϧʹ ClassMethods ͱ͍͏ Ϟδϡʔϧ͕͋Ε͹ɺͦΕΛextend͢Δ ✓ included {} ͱ͍͏ɺincludedϑοΫ ૬౰ͷΫϥεϚΫϩ͕͋Δ ActiveSupport::Concern

Slide 48

Slide 48 text

module MyModule included(base) "included by #{base}" end module ClassMethods def hi; 'hello' ; end end end class MyClass include MyModule # => "included by MyClass" end MyClass.hi # => "hello" ActiveSupport::Concern

Slide 49

Slide 49 text

·ͱΊϦϑϨΫγϣϯ UPPMCPY ✓ RubyͷΫϥε͸ʮ΍ΘΒ͔͍ʯ ✓ ૢ࡞͢ΔͨΊͷϝιου͕ͨ͘͞Μ͋Δ ✓ ʮϝλϓϩάϥϛϯάRubyʯ͓͢͢Ί

Slide 50

Slide 50 text

࣮༻ϝλϓϩ άϥϛϯά

Slide 51

Slide 51 text

ϝλϓϩάϥ ϛϯάͷ མͱ݀͠

Slide 52

Slide 52 text

Book = Class.new do define_method(:initialize) do |attrs| attrs.each do |key, value| if respond_to?("#{key}=") send("#{key}=", value) else instance_variable_set("@#{key}", value) end end end define_method(:price=) do |price_str| instance_variable_set( '@price', price_str.delete(',').to_i ) end end p Book.new(author: 'moro', price: '1,980')

Slide 53

Slide 53 text

class Book def initialize(attrs) @author = attrs[:author] self.price = attrs[:price] end def price=(price_str) @price = Integer(price_str.delete(',')) end end Book.new(author: 'moro', price: '1,980') #=> #

Slide 54

Slide 54 text

✓ ϝλϓϩάϥϛϯάͷ ίʔυ͸"೉͍͠" ✓ ͱΓΘ͚ϦϑϨΫγϣϯ ✓ sendظ, evalظ

Slide 55

Slide 55 text

ϝλʹߟ͑ͯ ϕλʹ࡞Δ

Slide 56

Slide 56 text

ActiveRecord::Base.has_many assoc_name assoc_name で指定された、複数の 子レコードへの関連を定義する。

Slide 57

Slide 57 text

class Books < ActiveRecord::Base has_many :reviews end Book#reviews #reviews= #review_ids #review_ids= ... Book#reviews.build reviews.create reviews.each {|review| ... } reviews.where(...) ͨ͘͞Μϝιου͕Ͱ͖Δ

Slide 58

Slide 58 text

def has_many(name, opts = {}) class_eval <<-RUBY def #{name} klass = #{name.to_s.classify} klass.where(#{fk}: id) end def #{name}=(value) values.each do |value| #{name.to_s.classify}.create!(...) end end RUBY end ೉ͦ͠͏ͳ࣮૷Πϝʔδ

Slide 59

Slide 59 text

ActiveRecord::Base.has_many assoc_name assoc_name で指定された、複数の 子レコードへの関連を扱うオブジェクトのための ラッパーメソッドを定義する。

Slide 60

Slide 60 text

Book#reviews ✓ ඥ෇͍͍ͯΔϨϏϡʔΛฦ͢ɺ ͷͰ͸ͳ͍ ✓ ਌ʹඥͮ͘ϨϏϡʔ͕͋Δͱ͍͏ ؔ࿈Λද͢ΦϒδΣΫτΛฦ͢

Slide 61

Slide 61 text

def define_readers mixin.class_eval <<-CODE, __FILE__, __LINE__ + def #{name}(*args) association(:#{name}).reader(*args) end CODE end ؔ࿈Λද͢ ΦϒδΣΫτΛฦ͢

Slide 62

Slide 62 text

Associationͷநग़ ✓ owner ͱ target ͕͍Δ ✓ owner ͷ id ͱtarget ͷ fk Ͱݕࡧ ͢Δ scope Λ࡞Δ ✓ target Λϩʔυ͠ɺద੾ʹϝϞԽ ✓ ௥Ճ࡟আͷίʔϧόοΫΛ؅ཧ͢Δ

Slide 63

Slide 63 text

= Active Record Associations This is the root class of all associations ('+ Foo' signifies an included module Foo): Association SingularAssociation HasOneAssociation HasOneThroughAssociation + ThroughAssociation BelongsToAssociation BelongsToPolymorphicAssociation CollectionAssociation HasAndBelongsToManyAssociation HasManyAssociation HasManyThroughAssociation + ThroughAssociation

Slide 64

Slide 64 text

✓ ਌Ϩίʔυ͔ΒࢠϨίʔυΛ Ҿ͘ϝιουΛ࡞Δ ✓ ਌ϨίʔυͱࢠϨίʔυͱͷ ؔ࿈Λද͢ΫϥεΛ࡞Δ

Slide 65

Slide 65 text

def define_readers mixin.class_eval <<-CODE, __FILE__, __LINE__ + def #{name}(*args) association(:#{name}).reader(*args) end CODE end ϦϑϨΫγϣϯͰ ബ͍ϥούʔΛ࡞Δ

Slide 66

Slide 66 text

·ͱΊ ࣮༻ϝλϓϩάϥϛϯά ✓ ϝλʹߟ͑ͯϕλʹ࡞Δ ✓ ϦϑϨΫγϣϯͰͭͳ͙

Slide 67

Slide 67 text

ڞ௨ػೳͷ நग़

Slide 68

Slide 68 text

౤ߘνΣοΫ ػೳͷྫ

Slide 69

Slide 69 text

✓ هࣄ(Post)ͱίϝϯτ(Comment)ͱ ը૾(Photo)ͷ౤ߘ಺༰ΛνΣοΫ ✓ ͦΕͧΕ͝ͱͷ಺༰Ͱ֎෦αʔϏ εʹ౤ߘ͍ͨ͠ ✓ Post͸λΠτϧͱຊจɺίϝϯτ͸ຊ จɺը૾͸දࣔURL

Slide 70

Slide 70 text

class Post < AR::Base after_save :submit_content_monitoring private def submit_content_monitoring content = [title, body].join("\n\n") url = Rails.config.censoring_endpoint req = Net::HTTP::Post.new(url.path) req.set_form_data('content' => content) Net::HTTP.start(url.hostname, url.port) do |htt http.request(req) end end

Slide 71

Slide 71 text

class Comment < AR::Base ... def submit_content_monitoring content = body ... end end class Photo < AR::Base ... def submit_content_monitoring content = "" ... end end

Slide 72

Slide 72 text

ڞ௨෦෼Λ ୳͢

Slide 73

Slide 73 text

class Post < AR::Base after_save :submit_content_monitoring private def submit_content_monitoring content = [title, body].join("\n\n") url = Rails.config.censoring_endpoint req = Net::HTTP::Post.new(url.path) req.set_form_data('content' => content) Net::HTTP.start(url.hostname, url.port) do |htt http.request(req) end end

Slide 74

Slide 74 text

class Post < AR::Base after_save :submit_content_monitoring private def submit_content_monitoring Censoring.new( [title, body].join("\n\n"), Rails.config.censoring_endpoint ).submit end end

Slide 75

Slide 75 text

class Censoring def initialize(content, url) @content = content @url = url end def submit req = Net::HTTP::Post.new(@url.path) req.set_form_data('content' => @content) Net::HTTP.start(@url.hostname, @url.port) do |h http.request(req) end end end

Slide 76

Slide 76 text

class Post < AR::Base after_save :submit_content_monitoring private def submit_content_monitoring Censoring.new( [title, body].join("\n\n"), Rails.config.censoring_endpoint ).submit end end

Slide 77

Slide 77 text

ϝλʹߟ͑ͯϕλʹ࡞Δ ର৅Ϋϥε͝ͱʹɺ౤ߘ νΣοΫ಺༰Λ૊Έཱͯ ૹ৴͢ΔΫϥε͕΄͍͠

Slide 78

Slide 78 text

class CensorAdapter def initialize(endpoint, &block) @endpoint = endpoint @content_builder = block end def submit(record) content = @content_builder.call(record) Censoring.new(content, @endpoint).submit end end # ---------------- post_adapter = CensorAdapter.new(endpoint) do |post| [post.title, post.body].join("\n\n") end post_adapter.submit(post)

Slide 79

Slide 79 text

class Post < AR::Base @@censor_adapter = CensorAdapter.new(config.endpoint) do |post| [post.title, post.body].join("\n\n") end after_save :submit_content_monitoring private def submit_content_monitoring @@censor_adapter.submit(self) end end

Slide 80

Slide 80 text

class Comment < AR::Base @@censor_adapter = CensorAdapter.new(config.endpoint) do |comment| comment.body end after_save :submit_content_monitoring private def submit_content_monitoring @@censor_adapter.submit(self) end end

Slide 81

Slide 81 text

class Photo < AR::Base @@censor_adapter = CensorAdapter.new(config.endpoint) do |photo| "" end after_save :submit_content_monitoring private def submit_content_monitoring @@censor_adapter.submit(self) end end

Slide 82

Slide 82 text

ϦϑϨΫγϣϯͰͭͳ͛Δ ౤ߘ͢ΔͨΊͷϝιουΛ ௥Ճͯ͠·ΘΔͷΛɺͳΜ ͱ͔Ͱ͖ͳ͍͔

Slide 83

Slide 83 text

module CeonsoringDsl def censor_content(url, &block) adapter = CensorAdapter.new(url, block) after_save {|record| adapter.submit(record) } end end

Slide 84

Slide 84 text

class Post < AR::Base extend CensoringDsl censor_content(config.endpoint) do |post| [post.title, post.body].join("\n\n") end end

Slide 85

Slide 85 text

QSPUJQ ࡞͍ͬͨΖΜͳΫϥεΛ $PODFSOʹ·ͱΊΔ

Slide 86

Slide 86 text

module Censorable extend ActiveSupport::Concern module ClassMethods def censor_content(url, &block) adapter = Censorable::Adapter.new(url, block after_save {|record| adapter.submit(record) end end class Adapter ... class Request ... end

Slide 87

Slide 87 text

class Post < ActiveRecord::Base include Censorable censor_content(config.censoring_endpoint) do |pos [post.title, post.body].join("\n\n") end end

Slide 88

Slide 88 text

·ͱΊ ڞ௨ػೳͷநग़ ✓ ϝλʹߟ͑ͯϕλʹ࡞Δ ✓ ϦϑϨΫγϣϯͰͭͳ͙

Slide 89

Slide 89 text

ϥΠϒϥϦͷ ࡞Γํ

Slide 90

Slide 90 text

আʑʹ ΞϓϦ಺ ϥΠϒϥϦ΁

Slide 91

Slide 91 text

ػೳΛผϑΝΠϧʹ෼͚ͨ͹͔Γ ΞϓϦඇґଘʹͨ͠΋ͷ app/** lib/** gem

Slide 92

Slide 92 text

app/** ʹ͋ΔϥΠϒϥϦ ✓ ࠷ॳʹநग़ͨ͠ػೳ͸app/ models ͳͲʹஔ͚Δ ✓ AR::BaseΛܧঝ͍ͯ͠ͳ͍Ϟσ ϧ΋͋ͬͯΑ͍!

Slide 93

Slide 93 text

lib/**ʹ΋͍ͬͯ͘ ✓ ΞϓϦ΁ͷґଘΛͳ͘͢ ✓ ౰વͳ͕ΒɺΞϓϦ͸ϥΠϒϥϦʹґଘ ͍ͯ͠Δ ✓ LOAD_PATH͸௨͍ͬͯΔͷͰ ͦͷ··͍͚࣋ͬͯΔ

Slide 94

Slide 94 text

HFN΁

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

✓ ར༻͍ͯ͠ΔgemͷɺҰࣜ૊Έ ߹Θͤ(bundle)Λ؅ཧ͢Δ ✓ όʔδϣϯ΍ೖख৔ॴ΋؅ཧͰ͖Δ ✓ gemͷͻͳܗ͕Ͱ͖Δ

Slide 97

Slide 97 text

✓ ΠϚυΩͬΆ͍σΟϨΫτϦߏ଄Ͱɺ gemͷͻͳܗ͕Ͱ͖Δ ✓ gemͷϝλσʔλϑΝΠϧ*.gemspec ΛຒΊΔ͚ͩͰgem͕Ͱ͖Δ $ bundle gem name

Slide 98

Slide 98 text

$ bundle gem censorable create censorable/Gemfile create censorable/Rakefile create censorable/LICENSE.txt create censorable/README.md create censorable/.gitignore create censorable/censorable.gemspec create censorable/lib/censorable.rb create censorable/lib/censorable/version.rb Initializating git repo in /Users/moro/tmp/censorab

Slide 99

Slide 99 text

Gem::Specification.new do |spec| spec.name = "censorable" spec.version = Censorable::VERSION spec.authors = ["moro"] spec.email = ["[email protected]"] spec.description = %q{TODO: Write a gem descrip spec.summary = %q{TODO: Write a gem summary spec.homepage = "" spec.license = "MIT" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { spec.test_files = spec.files.grep(%r{^(test|sp spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1. spec.add_development_dependency "rake"

Slide 100

Slide 100 text

$ bundle exec rake build censorable 0.0.1 built to pkg/censorable-0.0.1.gem. # rubygems.orgのアカウントがあればすぐ公開できる $ bundle exec rake release ͱͯ΋؆୯ʹgem͕Ͱ͖Δ

Slide 101

Slide 101 text

$ bundle gem censorable create censorable/Gemfile create censorable/Rakefile create censorable/LICENSE.txt create censorable/README.md create censorable/.gitignore create censorable/censorable.gemspec create censorable/lib/censorable.rb create censorable/lib/censorable/version.rb Initializating git repo in /Users/moro/tmp/censorab ͋ͱ͸libͷԼʹ ಺༰Λ࣋ͬͯ͘Δ͚ͩ

Slide 102

Slide 102 text

$ bundle gem censorable create censorable/Gemfile create censorable/Rakefile create censorable/LICENSE.txt create censorable/README.md create censorable/.gitignore create censorable/censorable.gemspec create censorable/lib/censorable.rb create censorable/lib/censorable/version.rb Initializating git repo in /Users/moro/tmp/censorab όʔδϣϯ͸͜ͷ ϑΝΠϧʹॻ͍͍ͯ͘

Slide 103

Slide 103 text

$ cat lib/censorable/version.rb module Censorable VERSION = "0.0.1" end

Slide 104

Slide 104 text

gem 'censorable', path:'/Users/moro/tmp/censorable' or gem 'censorable', github: 'moro/censorable' or gem 'censorable', git: 'git://github.com/moro/censo Gem leʹ௥Ճ͢Ε͹OK

Slide 105

Slide 105 text

ػೳΛผϑΝΠϧʹ෼͚ͨ͹͔Γ ΞϓϦඇґଘʹͨ͠΋ͷ ผHFNʹͯ͠ΈΔςετ ࣾ಺ڞ௨ϥΠϒϥϦͳͲ ੈʹ޿͘ϦϦʔεͨ͠ϥΠϒϥϦ app/** lib/** gem+path: gem+git: gem

Slide 106

Slide 106 text

·ͱΊϥΠϒϥϦͷ࡞Γํ ✓ ΞϓϦέʔγϣϯ͔Β আʑʹநग़͠ɺlibʹ͍࣋ͬͯ͘ ✓ gemʹ͢Δʹ͸ɺ࡞Δͱ͖΋࢖ ͏࣌΋bundlerΛ׆༻͢Δ

Slide 107

Slide 107 text

·ͱΊ

Slide 108

Slide 108 text

ࠓ೔ͷΰʔϧ

Slide 109

Slide 109 text

✓ RubyͰ͸ϝλϓϩάϥϛϯά͸";ͭ ͏"ͩͱࢥ͑ΔΑ͏ʹͳΔ ✓ ϝλϓϩάϥϛϯά༻ͷRubyͷػೳʹͭ ͍ͯɺུ֓Λ͔ͭΉ ✓ ࣮ફతʹϝλϓϩάϥϛϯά͢Δͱ͖ͷ ஫ҙ఺ɾߟ͑ํΛཧղ͢Δ

Slide 110

Slide 110 text

3VCZ΍3BJMTͷ։ൃͰ͸ɺ ϝλϓϩάϥϛϯάͱɺͦ͏ Ͱͳ͍΋ͷͷ۠ผ͸ᐆດɻ

Slide 111

Slide 111 text

͍ͭ΋࢖͍ͬͯΔػೳ͕ɺ ࣮͸ಈతϝιουఆٛͩͬ ͨΓ͢Δ͠ɺͦΕΛࣗ෼Ͱ ࡞Δ͜ͱ΋؆୯

Slide 112

Slide 112 text

ͦ͜Ͱ΍Γա͗ͳ͍ͨΊʹɺ ʮϝλʹߟ͑ϕλʹॻ͘ʯ͜ ͱΛ৺͕͚Δ (͍ͬΆ͏ͰϦϑϨΫγϣϯΛ࢖͍·͘Δ "࿅श"΋ͯ͠ΈΔͱͨͷ͍͠Ͱ͢)

Slide 113

Slide 113 text

แׅతͳ׬੒඼Λ໨ࢦ͢ͷ Ͱ͸ͳ͘ɺ࣮ΞϓϦͷػೳ Λɺগͣͭ͠஫ҙਂ͘ ϝλʹ͍ͯ͘͠ͷ͕େࣄ

Slide 114

Slide 114 text

ͦΕ͕Ͱ͖Δॊೈੑ͕ 3VCZͷྑ͞

Slide 115

Slide 115 text

“Ruby͸܅Λ৴པ͢ΔɻRuby͸܅Λ ෼ผͷ͋ΔϓϩάϥϚͱͯ͠ѻ͏ɻ Ruby͸ϝλϓϩάϥϛϯάͷΑ͏ͳ ڧྗͳྗΛ༩͑Δɻͨͩ͠ɺେ͍ͳ Δྗʹ͸ɺେ͍ͳΔ੹೚͕൐͏͜ͱ Λ๨Εͯ͸͍͚ͳ͍ɻͦΕͰ͸ɺ RubyͰͨͷ͍͠ϓϩάϥϛϯάΛɻ ʮϝλϓϩάϥϛϯάRubyʯ ংจΑΓ Matz says: