- 浏览: 307344 次
文章分类
最新评论
-
shoru:
最新的netbeans scala插件无法安装到6.9中呀,求 ...
Scala-对Java的修正和超越-Presentation -
alanwu:
night_stalker 写道讲一次多少钱啊,能透露下么…… ...
Scala-对Java的修正和超越-Presentation -
wzjin:
暂时没有考虑学习,等有一定市场再看!
Scala-对Java的修正和超越-Presentation -
dcaoyuan:
jasspier 写道对scala有点兴趣,有没有入门的推荐教 ...
Scala-对Java的修正和超越-Presentation -
jasspier:
草原兄,听了你的课,对scala有点兴趣,有没有入门的推荐教程 ...
Scala-对Java的修正和超越-Presentation
3. The Magic Behind Erlyweb
With dynamic typing, hot code swapping, built-in parsing and compilation tools, Erlang is also suitable for dynamic meta-programming. Erlyweb uses a small convenient tool smerl to generate db record CRUD code automatically.
The music example on erlyweb.org shows the magic:
Define a simple musician.erl module (just one line here):
-module(musician).
Then, you will get a long list functions for musician module after erlyweb:compile("apps/music"). Sounds similar to Rails.
I like to watch magic show, but I can't stand that I do not know the things behind magic in programming. For Rails, the magic behind it always makes me headache, it's too difficult to follow who, where, some code are injected into a class or module. But in Erlang, it's super easy.
I add a simple function to erlyweb_app.erl (please see my previous post):
-export([decompile/2]). decompile(AppName, Beam) when is_atom(AppName) -> decompile(atom_to_list(AppName), Beam); decompile(AppName, Beam) when is_list(AppName) -> BinFilename = "./apps/" ++ AppName ++ "/ebin/" ++ atom_to_list(Beam), io:format("Beam file: ~s~n", [BinFilename]), {ok, {_, [{abstract_code, {_, AC}}]}} = beam_lib:chunks(BinFilename, [abstract_code]), SrcFilename = "./apps/" ++ AppName ++ "_" ++ atom_to_list(Beam), {ok, S} = file:open(SrcFilename ++ ".erl", write), io:fwrite(S, "~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
Now type erlyweb_decompile(music, musician) under the Erlang shell, I get a file: music_musician.erl under folder myproject/apps/ (I put these decompiled source files under /myproject/apps/ to avoid that they are auto-compiled to beams by erlyweb again ):
-file("musician", 1). -module(musician). -export([relations/0, fields/0, table/0, type_field/0, db_table/0, db_field/1, is_new/1, is_new/2, get_module/1, to_iolist/1, to_iolist/2, field_to_iolist/2, new/0, new_with/1, new_with/2, new_from_strings/1, set_fields/2, set_fields/3, set_fields_from_strs/2, field_from_string/2, save/1, insert/1, update/1, update/2, delete/1, delete_id/1, delete_where/1, delete_all/0, transaction/1, before_save/1, after_save/1, before_delete/1, after_delete/1, after_fetch/1, find/2, find_first/2, find_max/3, find_range/4, find_id/1, aggregate/4, count/0, get/2, set_related_one_to_many/2, find_related_one_to_many/2, find_related_many_to_one/4, aggregate_related_many_to_one/6, add_related_many_to_many/3, remove_related_many_to_many/3, remove_related_many_to_many_all/5, find_related_many_to_many/5, aggregate_related_many_to_many/7, find_related_many_first/4, find_related_many_max/5, find_related_many_range/6, aggregate_related_many/6, do_save/1, do_delete/1, field_names_for_query/0, field_names_for_query/1, field_to_iolist/1, set/3, db_pk_fields/0, get_pk_fk_fields/0, get_pk_fk_fields2/0, db_fields/0, db_field_names/0, db_field_names_str/0, db_field_names_bin/0, db_num_fields/0, id/1, id/2, name/1, name/2, birth_date/1, birth_date/2, instrument/1, instrument/2, bio/1, bio/2, new/4, driver/0, count/3, count/1, count/2, count_with/2, avg/3, avg/1, avg/2, avg_with/2, min/3, min/1, min/2, min_with/2, max/3, max/1, max/2, max_with/2, sum/3, sum/1, sum/2, sum_with/2, stddev/3, stddev/1, stddev/2, stddev_with/2, find/0, find/1, find_with/1, find_first/0, find_first/1, find_first_with/1, find_max/1, find_max/2, find_max_with/2, find_range/2, find_range/3, find_range_with/3]). relations() -> erlydb_base:relations(). fields() -> erlydb_base:fields(). table() -> erlydb_base:table(). type_field() -> erlydb_base:type_field(). db_table() -> erlydb_base:db_table(musician). db_field(FieldName) -> erlydb_base:db_field(musician, FieldName). is_new(Rec) -> erlydb_base:is_new(Rec). is_new(Rec, Val) -> erlydb_base:is_new(Rec, Val). get_module(Rec) -> erlydb_base:get_module(Rec). to_iolist(Recs) -> erlydb_base:to_iolist(musician, Recs). to_iolist(Recs, ToIolistFun) -> erlydb_base:to_iolist(musician, Recs, ToIolistFun). field_to_iolist(Val, _Field) -> erlydb_base:field_to_iolist(Val, _Field). new() -> erlydb_base:new(musician). new_with(Fields) -> erlydb_base:new_with(musician, Fields). new_with(Fields, ToFieldFun) -> erlydb_base:new_with(musician, Fields, ToFieldFun). new_from_strings(Fields) -> erlydb_base:new_from_strings(musician, Fields). set_fields(Record, Fields) -> erlydb_base:set_fields(musician, Record, Fields). set_fields(Record, Fields, ToFieldFun) -> erlydb_base:set_fields(musician, Record, Fields, ToFieldFun). set_fields_from_strs(Record, Fields) -> erlydb_base:set_fields_from_strs(musician, Record, Fields). field_from_string(ErlyDbField, undefined) -> erlydb_base:field_from_string(ErlyDbField, undefined). save(Rec) -> erlydb_base:save(Rec). insert(Recs) -> erlydb_base:insert(Recs). update(Props) -> erlydb_base:update(musician, Props). update(Props, Where) -> erlydb_base:update(musician, Props, Where). delete(Rec) -> erlydb_base:delete(Rec). delete_id(Id) -> erlydb_base:delete_id(musician, Id). delete_where(Where) -> erlydb_base:delete_where(musician, Where). delete_all() -> erlydb_base:delete_all(musician). transaction(Fun) -> erlydb_base:transaction(musician, Fun). before_save(Rec) -> erlydb_base:before_save(Rec). after_save(Rec) -> erlydb_base:after_save(Rec). before_delete(Rec) -> erlydb_base:before_delete(Rec). after_delete({_Rec, Num}) -> erlydb_base:after_delete({_Rec, Num}). after_fetch(Rec) -> erlydb_base:after_fetch(Rec). find(Where, Extras) -> erlydb_base:find(musician, Where, Extras). find_first(Where, Extras) -> erlydb_base:find_first(musician, Where, Extras). find_max(Max, Where, Extras) -> erlydb_base:find_max(musician, Max, Where, Extras). find_range(First, Max, Where, Extras) -> erlydb_base:find_range(musician, First, Max, Where, Extras). find_id(Id) -> erlydb_base:find_id(musician, Id). aggregate(AggFunc, Field, Where, Extras) -> erlydb_base:aggregate(musician, AggFunc, Field, Where, Extras). count() -> erlydb_base:count(musician). get(Idx, Rec) -> erlydb_base:get(Idx, Rec). set_related_one_to_many(Rec, Other) -> erlydb_base:set_related_one_to_many(Rec, Other). find_related_one_to_many(OtherModule, Rec) -> erlydb_base:find_related_one_to_many(OtherModule, Rec). find_related_many_to_one(OtherModule, Rec, Where, Extras) -> erlydb_base:find_related_many_to_one(OtherModule, Rec, Where, Extras). aggregate_related_many_to_one(OtherModule, AggFunc, Rec, Field, Where, Extras) -> erlydb_base:aggregate_related_many_to_one(OtherModule, AggFunc, Rec, Field, Where, Extras). add_related_many_to_many(JoinTable, Rec, OtherRec) -> erlydb_base:add_related_many_to_many(JoinTable, Rec, OtherRec). remove_related_many_to_many(JoinTable, Rec, OtherRec) -> erlydb_base:remove_related_many_to_many(JoinTable, Rec, OtherRec). remove_related_many_to_many_all(JoinTable, OtherTable, Rec, Where, Extras) -> erlydb_base:remove_related_many_to_many_all(JoinTable, OtherTable, Rec, Where, Extras). find_related_many_to_many(OtherModule, JoinTable, Rec, Where, Extras) -> erlydb_base:find_related_many_to_many(OtherModule, JoinTable, Rec, Where, Extras). aggregate_related_many_to_many(OtherModule, JoinTable, AggFunc, Rec, Field, Where, Extras) -> erlydb_base:aggregate_related_many_to_many(OtherModule, JoinTable, AggFunc, Rec, Field, Where, Extras). find_related_many_first(Func, Rec, Where, Extras) -> erlydb_base:find_related_many_first(Func, Rec, Where, Extras). find_related_many_max(Func, Rec, Num, Where, Extras) -> erlydb_base:find_related_many_max(Func, Rec, Num, Where, Extras). find_related_many_range(Func, Rec, First, Last, Where, Extras) -> erlydb_base:find_related_many_range(Func, Rec, First, Last, Where, Extras). aggregate_related_many(Func, AggFunc, Rec, Field, Where, Extras) -> erlydb_base:aggregate_related_many(Func, AggFunc, Rec, Field, Where, Extras). do_save(Rec) -> erlydb_base:do_save(Rec). do_delete(Rec) -> erlydb_base:do_delete(Rec). field_names_for_query() -> erlydb_base:field_names_for_query(musician). field_names_for_query(UseStar) -> erlydb_base:field_names_for_query(musician, UseStar). field_to_iolist(Val) -> erlydb_base:field_to_iolist(Val). set(Idx, Rec, Val) -> setelement(Idx, Rec, Val). db_pk_fields() -> erlydb_base:db_pk_fields([{erlydb_field, id, "id", <<105, 100>>, int, 11, integer, text_field, false, primary, undefined, identity}]). get_pk_fk_fields() -> erlydb_base:get_pk_fk_fields([{id, musician_id}]). get_pk_fk_fields2() -> erlydb_base:get_pk_fk_fields2([{id, musician_id1, musician_id2}]). db_fields() -> erlydb_base:db_fields([{erlydb_field, id, "id", <<105, 100>>, int, 11, integer, text_field, false, primary, undefined, identity}, {erlydb_field, name, "name", <<110, 97, 109, 101>>, varchar, 20, binary, text_field, true, undefined, undefined, undefined}, {erlydb_field, birth_date, "birth_date", <<98, 105, 114, 116, 104, 95, 100, 97, 116, 101>>, date, undefined, date, text_field, true, undefined, undefined, undefined}, {erlydb_field, instrument, "instrument", <<105, 110, 115, 116, 114, 117, 109, 101, 110, 116>>, enum, [<<103, 117, 105, 116, 97, 114>>, <<112, 105, 97, 110, 111>>, <<100, 114, 117, 109, 115>>, <<118, 111, 99, 97, 108, 115>>], binary, select, true, undefined, undefined, undefined}, {erlydb_field, bio, "bio", <<98, 105, 111>>, text, undefined, binary, text_area, true, undefined, undefined, undefined}]). db_field_names() -> erlydb_base:db_field_names([id, name, birth_date, instrument, bio]). db_field_names_str() -> erlydb_base:db_field_names_str(["id", "name", "birth_date", "instrument", "bio"]). db_field_names_bin() -> erlydb_base:db_field_names_bin([<<105, 100>>, <<110, 97, 109, 101>>, <<98, 105, 114, 116, 104, 95, 100, 97, 116, 101>>, <<105, 110, 115, 116, 114, 117, 109, 101, 110, 116>>, <<98, 105, 111>>]). db_num_fields() -> erlydb_base:db_num_fields(5). id(Rec) -> erlydb_base:get(3, Rec). id(Rec, Val) -> setelement(3, Rec, Val). name(Rec) -> erlydb_base:get(4, Rec). name(Rec, Val) -> setelement(4, Rec, Val). birth_date(Rec) -> erlydb_base:get(5, Rec). birth_date(Rec, Val) -> setelement(5, Rec, Val). instrument(Rec) -> erlydb_base:get(6, Rec). instrument(Rec, Val) -> setelement(6, Rec, Val). bio(Rec) -> erlydb_base:get(7, Rec). bio(Rec, Val) -> setelement(7, Rec, Val). new(name, birth_date, instrument, bio) -> {musician, true, undefined, name, birth_date, instrument, bio}. driver() -> erlydb_base:driver({erlydb_mysql, [{last_compile_time, {{1980, 1, 1}, {0, 0, 0}}}, {outdir, "apps/music/ebin"}, debug_info, report_errors, report_warnings, {erlydb_driver, mysql}]}). count(Field, Where, Extras) -> erlydb_base:aggregate(musician, count, Field, Where, Extras). count(Field) -> erlydb_base:aggregate(musician, count, Field, undefined, undefined). count(Field, Where) -> erlydb_base:aggregate(musician, count, Field, Where, undefined). count_with(Field, Extras) -> erlydb_base:aggregate(musician, count, Field, undefined, Extras). avg(Field, Where, Extras) -> erlydb_base:aggregate(musician, avg, Field, Where, Extras). avg(Field) -> erlydb_base:aggregate(musician, avg, Field, undefined, undefined). avg(Field, Where) -> erlydb_base:aggregate(musician, avg, Field, Where, undefined). avg_with(Field, Extras) -> erlydb_base:aggregate(musician, avg, Field, undefined, Extras). min(Field, Where, Extras) -> erlydb_base:aggregate(musician, min, Field, Where, Extras). min(Field) -> erlydb_base:aggregate(musician, min, Field, undefined, undefined). min(Field, Where) -> erlydb_base:aggregate(musician, min, Field, Where, undefined). min_with(Field, Extras) -> erlydb_base:aggregate(musician, min, Field, undefined, Extras). max(Field, Where, Extras) -> erlydb_base:aggregate(musician, max, Field, Where, Extras). max(Field) -> erlydb_base:aggregate(musician, max, Field, undefined, undefined). max(Field, Where) -> erlydb_base:aggregate(musician, max, Field, Where, undefined). max_with(Field, Extras) -> erlydb_base:aggregate(musician, max, Field, undefined, Extras). sum(Field, Where, Extras) -> erlydb_base:aggregate(musician, sum, Field, Where, Extras). sum(Field) -> erlydb_base:aggregate(musician, sum, Field, undefined, undefined). sum(Field, Where) -> erlydb_base:aggregate(musician, sum, Field, Where, undefined). sum_with(Field, Extras) -> erlydb_base:aggregate(musician, sum, Field, undefined, Extras). stddev(Field, Where, Extras) -> erlydb_base:aggregate(musician, stddev, Field, Where, Extras). stddev(Field) -> erlydb_base:aggregate(musician, stddev, Field, undefined, undefined). stddev(Field, Where) -> erlydb_base:aggregate(musician, stddev, Field, Where, undefined). stddev_with(Field, Extras) -> erlydb_base:aggregate(musician, stddev, Field, undefined, Extras). find() -> erlydb_base:find(musician, undefined, undefined). find(Where) -> erlydb_base:find(musician, Where, undefined). find_with(Extras) -> erlydb_base:find(musician, undefined, Extras). find_first() -> erlydb_base:find_first(musician, undefined, undefined). find_first(Where) -> erlydb_base:find_first(musician, Where, undefined). find_first_with(Extras) -> erlydb_base:find_first(musician, undefined, Extras). find_max(Max) -> erlydb_base:find_max(musician, Max, undefined, undefined). find_max(Max, Where) -> erlydb_base:find_max(musician, Max, Where, undefined). find_max_with(Max, Extras) -> erlydb_base:find_max(musician, Max, undefined, Extras). find_range(First, Max) -> erlydb_base:find_range(musician, First, Max, undefined, undefined). find_range(First, Max, Where) -> erlydb_base:find_range(musician, First, Max, Where, undefined). find_range_with(First, Max, Extras) -> erlydb_base:find_range(musician, First, Max, undefined, Extras).
With this decompiled file, you get all things clearly behind the magic, such as, you have pair getter/setter functions for each field, for example:
Musician = musician:find({name, 'like' "Caoyuan Mus"}), %% get the 'name' field of record Musician Name = musician:name(Musician), %% set the 'name' field to "new name" and bind to a new record Musician1. Musician1 = musician:name(Musician, "new name"), %% Or, Musician2 = musician:set_fields(Musician, {name, "new name"}, {birth_day, "1940/10/9"}), %% then save one of them musician:save(Musician2).
Finally, some notices for new comer to Erlang and Erlyweb:
- In Erlang, the Variable can only be bound(set value) once , so, only Musician1 and Musician2 have the "new name", Musician will keep the original value
- For efficiency reason, if the field is varchar/text type, the getter will return a binary rather than string, which can be printed on browser directly in Erlyweb, but, if you want to use it as a string, you can apply binary_to_list(Name) on it.
发表评论
-
Updated "From Rails to Erlyweb" Part I and Part II
2007-07-30 00:13 869I've updated "From Rails t ... -
From Rails to Erlyweb - Part IV
2007-07-30 00:14 916IV. Support Mysql Spatial Exten ... -
HTML Entity Refs and xmerl
2007-07-30 00:14 970According to [erlang-bugs] xme ... -
From Rails to Erlyweb - Part I
2007-08-05 06:34 1238Updated July 20 2007: new param ... -
ErlyBird 0.12.0 released - Erlang IDE based on NetBeans
2007-08-08 18:40 923I'm pleased to announce ErlyBir ... -
A Simple POET State Machine Accepting SAX Events to Build Plain Old Erlang Term
2007-08-20 07:19 1002Per previous blogs: A Simple ... -
A Simple XML State Machine Accepting SAX Events to Build xmerl Compitable XML Tree: icalendar demo
2007-08-20 07:23 1140xmerl is a full XML functionali ... -
recbird - An Erlang Dynamic Record Inferring Parse Transform
2007-08-23 08:31 1063You should have read Yariv's re ... -
From Rails to Erlyweb - Part II
2007-08-23 21:16 1277Updated Aug 23: Please see Fro ... -
From Rails to Erlyweb - Part II Manage Project - Reloaded
2007-08-24 19:20 1354The migrating from Rails to Erl ... -
Parse JSON to xmerl Compitable XML Tree via A Simple XML State Machine
2007-09-02 20:00 1540Updated Aug 16: Fix bugs when j ... -
Tim Bray's Erlang Exercise on Large Dataset Processing
2007-10-10 20:12 1254Updated Oct 10: pread_file/5 s ... -
Tim Bray's Erlang Exercise on Large Dataset Processing - Round II
2007-10-15 15:37 1627Updated Oct 09: Added more ben ... -
Reading File in Parallel in Erlang (Was Tim Bray's Erlang Exercise - Round III)
2007-10-15 19:56 1920My first solution for Tim's ex ... -
The Erlang Way (Was Tim Bray's Erlang Exercise - Round IV)
2007-10-17 07:45 1801Playing with Tim's Erlang Exerc ... -
Learning Coding Parallelization (Was Tim's Erlang Exercise - Round V)
2007-10-17 21:58 1570Updated Oct 16: After testing ...
相关推荐
rails-dev-box, 面向 Ruby on Rails 核心开发的虚拟机 用于 Ruby on Rails 核心开发的虚拟机简介注意:这个虚拟机不是为 Rails 应用程序开发而设计的,只是为。 这个项目自动设置开发环境,以便在 Ruby on Rails ...
rails-documentation-2-0-2
rails-beginner-s-guide是Rails 指导手册,帮组学习了解rails开发
用于Ruby on Rails核心开发的虚拟机 介绍 请注意,该虚拟机并非为...host $ cd rails-dev-box host $ vagrant up 而已。 安装完成后,您可以使用以下命令访问虚拟机: host $ vagrant ssh Welcome to Ubuntu 20.10
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
在本项目"rails应用--导航栏实例工程"中,我们将探讨如何在Ruby on Rails框架下构建一个实用的导航栏。Rails是一个流行的开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,使得开发过程更加高效且结构...
标题 "rails-documentation-1-2-1.zip" 暗示这是一份关于 Ruby on Rails 框架的文档,版本为 1.2.1。Ruby 是一种面向对象的编程语言,而 Rails 是一个基于 Ruby 的开源 Web 应用程序框架,遵循 Model-View-...
rails-documentation-1-2-0-rc1.chm
本文将深入探讨"rails-react-components-源码.rar"中的关键知识点,帮助开发者理解如何在Rails应用中集成React组件。 1. **React组件化开发** React的核心概念是组件,它允许我们将UI拆分为独立、可重用的部分。在...
rails-ftw-v0.18-2.1.5-4.1.8.exe用于在windows环境下搭建readmine环境
"rails-2.1.0-gem"是Rails框架的一个特定版本,即2.1.0的gem包,用于在Ruby环境中安装和管理Rails框架。 Rails的核心理念是“约定优于配置”(Convention over Configuration),这意味着开发者可以遵循一套预设的...
`rails-documentation-2-0-2.chm` 文件详细涵盖了这些概念,包含了关于Rails 2.0.2的API参考、教程和指南。通过仔细阅读和实践,开发者能够深入理解Rails的工作原理,并有效地开发出高效、可维护的Web应用。
标题 "rails-development-environment-master.rar" 暗示这是一个关于Ruby on Rails开发环境的压缩包。Rails是基于Ruby语言的一个开源Web应用框架,遵循MVC(Model-View-Controller)架构模式,广泛用于构建数据库...
【标题】"rails-yelp-mvp-源码" 指的是一个基于Rails框架开发的类似于Yelp(美国知名餐饮评论网站)的最小可行产品(Minimum Viable Product, MVP)的源代码。Rails是Ruby编程语言的一个流行Web开发框架,以其“约定...
"rails-playlists-源码"很可能是某个开发者或团队分享的关于音乐播放列表管理功能的示例代码或项目。在本文中,我们将深入探讨Rails框架的基本概念,以及如何通过源码理解其在实现播放列表功能时的核心技术。 1. **...
### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...
rails-nginx-passenger-ubuntu, 关于如何在 Nginx 8.04服务器上启动和运行和乘客的说明 rails-nginx-passenger-ubuntu我关于用 ubuntu 。Nginx 。乘客和mysql建立 Rails的简单制作服务器的笔记。别名echo"alias ll='...
Ajax-Rails-4-AJAX-Form.zip,rails 4 ajax表单示例,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建动态网页,其中网页的小部分在不重新加载网页的情况下...
rails-event-sourcing-example, 带有RabbitMQ的Rails 事件 RabbitMQ事件源示例 运行示例 1确保已经安装并运行 RabbitMQ在macosx上,你可以使用 Homebrew 安装 RabbitMQ$ brew install rabbitmq开始使用$/u
railstutorial3rd-1.0.2 分享给大家了