Skip to content

5alamander/cluby

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cluby -- Ruby Object Model in Clojure

A Clojure library designed to simulate the OO model of Ruby.

在使用clojure描述问题时,经常遇到一些需要反引用的场景,每当这个时候,就十分怀念OOP呢。

于是就写了这个包,目的在于在Clojure中模仿Ruby的对象模型的构建。

  • 注: 仅用于在Clojure中构建对象模型,其他内容还是使用Clojure和Java的东西比较合适

Latest version

Install

下载:在project.clj中添加依赖,如下

:dependencies [org.clojars.sa1amander/cluby "0.1.0-SNAPSHOT"]

Usage

方法调用

只能说尽量保持语法一致了

#ruby
Object.new() 
MyClass.new(1)

#clojure
(OBJECT :new)
(MyClass :new 1)

创建对象

从OBJECT, 和MODULE, 对象类中新建

  • 注:OBJECT, CLASS, MODULE, BASIC-OBJECT,这几个基本的类用大写
  • (Object 与java的Object冲突了。。。)
;; clojure
(def obj (OBJECT :allocate))
(def module (MODULE :allocate))
# ruby
obj = Object.allocate
mod = Module.allocate

定义类实例方法

定义类,和类的实例方法instance-methods,

方法定义直接使用clojure内置function,等效于 (fn [ ] ... ) ,直接使用原生的重载方法

多了一对括号,方便解析,以后省掉吧,囧

  • TODO: 定义新的defm宏
;; clojure
(defclass MyClass
    (defm method1 ([] :m))
    (defm multimethod (     ;; 不同参数个数的重载方法
        ([a] :m1)
        ([] :m0))))

(def my-obj (MyClass :new))
(my-obj :method1)           ;=> :m
(my-obj :multimethod 1)     ;=> :m1
(my-obj :multimethod)       ;=> :m0

在不使用黑魔法的前提下,ruby没有原生的重载方法(ruby黑魔法实现

关于参数个数的问题请参考Proc#arity

# ruby
class MyClass
    def method1()
        :m
    end
  ## def multimethod        # 没有重载方法
end

myObj = MyClass.new
myObj.method1               #=> :m

---为什么叫黑魔法呢,因为接下来就会遇到问题

定义方法到类对象上(实例方法)

单件类(eigenclass,singleton_class):叫法比较多,还是教单件类好听些

;; clojure
(defm MyClass a ([]
    :MyClass-method))
(MyClass :a)            	;=> :MyClass-method
# ruby
def MyClass.a()
    :MyClass-method
end
MyClass.a()		     		#=> :MyClass-method

子类可以使用超类的单件方法

这个特性怎么能少

;; clojure
(defclass MySubClass (extends MyClass))
(MySubClass :a)            	;=> :MyClass-method
# ruby
class MySubClass < MyClass
end
MySubClass.a()		     	#=> :MyClass-method

定义方法到对象上(单件方法)

;; clojure
(def my-obj (MyClass :new))
(defm my-obj a ([]
    :my-obj-method))
(my-obj :a)            	    ;=> :my-obj-method
# ruby
myObj = MyClass.new
def myObj.a()
    :my-obj-method
end
myObj.a()		     		#=> :my-obj-method

类的继承

在类定义中用(extends MyClass)表示继承[任意位置,如果存在多个则最后一个生效]

使用(self :super ....)调用超类中的方法,

非常遗憾的是,重载方法会被子类的新的方法一次性覆盖掉,与常理不符合

上文所述的ruby黑魔法也有这个问题,黑魔法的副作用啊o(╯□╰)o

  • TODO: 使用<符号表示继承
;; clojure
(defclass SubClass (extends MyClass)
	(defm method1 ([]
		[:sub, (self :super :method1)])))
# ruby
class SubClass < MyClass
	def method1()
		[:sub, super.method1()]
	end
end

Mixin

module会被添加到先祖链上

;; clojure
(defmodule Amodule
	(defm a ([] :module-a)))
(defclass Empty
	(include Amodule))
# ruby
module Amodule
	def a (); :module-a ; end
end
class Empty
	include Amodule
end

实例对象上添加module

module会被添加到实例的eigenclass上

;; clojure
(my-obj :extend Amodule)
# ruby
myObj.extend(Amodule)

Awesome Features with Clojure

Delegate

由于对象是fn包装而成的,所以一切有关函数的特性都适用, 使用partial函数的来模拟delegate特性(还是带柯里化的delegate)

(defclass MyClass
	(defm initialize ([]
		(self :set! :t 1)))
	(defm a ([]
    	(self :get :t)))
	(defm b ([arg1 arg2]
    	(+ arg1 arg2))))

;; 新建对象
(def my-obj (MyClass :new))

;; 创建delegate
(def delegate0 (partial my-obj :a))
(def delegate1 (partial my-obj :b))
(def delegate2 (partial my-obj :b 10))

(delegate0)          ; => 1
(delegate1 4 5)      ; => 9
(delegate2 4)        ; => 14

PersistenceMap

实例对象的变量键值对,使用原生map类型保存,可以直接设置

(def obj1 (MyClass :new))
(set-states obj1 {:a 1, :b 2, :c 3}) ; 直接设置
(obj1 :get :a)  ; => 1
(obj1 :set! :a 2)
(obj1 :get :a)  ; => 2

...

License

Copyright © 2016 FIXME

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

About

Ruby Object Model

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published