First version of BeginnersGuide and other doc changes
This commit is contained in:
parent
a40d8f2e8c
commit
f2c853821c
238
BeginnersGuide.md
Normal file
238
BeginnersGuide.md
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
# Beginners Guide
|
||||||
|
|
||||||
|
We are coming up to RailsGirlsSummerOfCode, so i wrote this document for people with
|
||||||
|
very little coding or ruby experience. It can be used by other people as a check-list,
|
||||||
|
because basically anything in here is assumed when working on RubyX.
|
||||||
|
|
||||||
|
# Tools of the trade
|
||||||
|
|
||||||
|
I just want to introduce the main characters, what you need, maybe some extra.
|
||||||
|
Details for installing or using software are abound on the net, so i am not getting
|
||||||
|
into specifics, platform issues or the like. Just an overview that you may not find
|
||||||
|
on the net.
|
||||||
|
|
||||||
|
## Terminal
|
||||||
|
|
||||||
|
The terminal and editor are still the two main tools you need. A terminal is a program
|
||||||
|
that interprets typed input and starts other programs. The interpreters are called
|
||||||
|
shells, bash (Bourne Again SHell) is popular, but anything you have is fine.
|
||||||
|
|
||||||
|
The shell starts when you start a terminal (window or tab) and usually reads somehting
|
||||||
|
like .profile, or .bash_profile , where environment variables may be set. These
|
||||||
|
variables, usually with capital names, influence the behaviour of programs. The most
|
||||||
|
import one is probably the PATH variable, that determines where program executables
|
||||||
|
are searched.
|
||||||
|
|
||||||
|
Don't fuss in the beginning which terminal you use, anything is fine for starters.
|
||||||
|
|
||||||
|
When i talk about commands, i mean typing those commands in the terminal.
|
||||||
|
|
||||||
|
## Editor
|
||||||
|
|
||||||
|
Off course you need an editor to edit program files. The most important thing here is
|
||||||
|
that it supports colour highlighting for ruby. It may be an IDE like RubyMine, vim, or
|
||||||
|
i use atom. It does not really matter, as long as you know how to use it.
|
||||||
|
|
||||||
|
## Ruby, maybe with versions
|
||||||
|
|
||||||
|
There are two main ruby implementations, called MRI (Matz Ruby implementations) and
|
||||||
|
JRuby (Java Ruby), we will use MRI.
|
||||||
|
|
||||||
|
There are several versions of MRI, though that used to matter more than it does now.
|
||||||
|
Anything over 2.4 is fine for RubyX.
|
||||||
|
|
||||||
|
Because version differences were bigger, and in a professional environment it is
|
||||||
|
essential to know the exact version on is using (in development and production)
|
||||||
|
ruby version managers have been developed. There are rbenv and rvm , but since
|
||||||
|
you don't really need them i will leave it at that.
|
||||||
|
|
||||||
|
## Gems
|
||||||
|
|
||||||
|
Gems are packages of ruby code. After all, any meaningful software will rely on other
|
||||||
|
software, and so gems have been with ruby from the start as a way of packaging code.
|
||||||
|
|
||||||
|
Eg rubyx is a gem, and you can see the package definition in rubyx.gemspec in the root
|
||||||
|
folder.
|
||||||
|
|
||||||
|
gem is also a command to manage gems. A version of gem (the command) will come with
|
||||||
|
any ruby installation. gem is used to manage single packages, but for a project
|
||||||
|
we usually need many gems, and this is where bundler comes in.
|
||||||
|
|
||||||
|
## Bundler
|
||||||
|
|
||||||
|
Bundler is a program (a gem actually) to manage all the gems a project needs. The
|
||||||
|
problem it was made to solve is this: Say you need 10 gems for a project. Those 10
|
||||||
|
gems all have dependencies of their own, so really you may need 20-40 gems.
|
||||||
|
If not managed, different developers and production systems will have slightly
|
||||||
|
different versions of gems. This leads to very hard to track errors, a nightmare
|
||||||
|
basically.
|
||||||
|
|
||||||
|
A Gemfile is the bundlers way of specifying a projects dependencies. Bundler
|
||||||
|
(using the command bundle install) then resolves all dependencies and their
|
||||||
|
dependencies and installs all the needed gems.
|
||||||
|
|
||||||
|
Bundler also creates a Gemfile.lock to record all the gems that are needed. This file
|
||||||
|
is usually checked in and will ensure that every developer has the same gems.
|
||||||
|
|
||||||
|
Only when the Gemfile is changed, or one wants to update gems by hand, does bundle
|
||||||
|
install need to be run again.
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
Version control has always been essential to coordinate the work of many people,
|
||||||
|
and git is arguably the best tool for the job. So you need to install it and get
|
||||||
|
to know the basics, at least clone, commit, push, and basic branches.
|
||||||
|
|
||||||
|
After installing MRI and bundler you need to clone the rubyx repository.
|
||||||
|
Go to the directory and bundle (or bundle install, sama sama)
|
||||||
|
|
||||||
|
Then you can run "ruby test/test_all.rb" to determine that everything is working as it
|
||||||
|
should. If it does, you are ready to start development.
|
||||||
|
|
||||||
|
# Development process
|
||||||
|
|
||||||
|
Once you have a working environment, you'll be wanting to code. So this section is
|
||||||
|
about the basic loops we go through as developers, the recurring tasks that make
|
||||||
|
up a programmers life. I'll try to avoid jargon and rather explain why we do what we do.
|
||||||
|
|
||||||
|
## Edit => Save
|
||||||
|
|
||||||
|
The most basic cycle is undoubtedly edit and save. You edit some part of the program
|
||||||
|
and save your work. There are some details to consider about the formatting and style,
|
||||||
|
in the [Code Style](CodeStyle.md).
|
||||||
|
|
||||||
|
There are two basic needs to do this basic coding:
|
||||||
|
- you need to know what to edit, what it is you want to achieve and how to achieve it
|
||||||
|
- having finished (saved) you need a way to know if you have achieved what you set out to do
|
||||||
|
|
||||||
|
The "how to achieve it" part is the skill of programming. Like all skills, developing
|
||||||
|
this skill is a process and takes years, so i'll leave it at that.
|
||||||
|
|
||||||
|
What you want to achieve is up to you. Your imagination for the new. Your ability to
|
||||||
|
find bugs. Or your willingness to do what others have found worthy of doing (issues).
|
||||||
|
This is explained more in the next section.
|
||||||
|
|
||||||
|
So then we come to that crucial part of knowing when you achieved your goal. This has
|
||||||
|
been at the crux of programming since the dawn, and the most widely agreed upon way is
|
||||||
|
off course testing. Everybody agrees testing is the way, just how much is in dispute.
|
||||||
|
It's like being healthy: everybody agrees in principle, but many still smoke, or
|
||||||
|
eat meat or milk products (clearly shown to be unhealthy)
|
||||||
|
|
||||||
|
## Testing (or edit => save => test)
|
||||||
|
|
||||||
|
RubyX is very clear on the topic: all code needs tests. All new code needs new test.
|
||||||
|
Every bug-fix needs more tests. Tests are the only way we know things work, and
|
||||||
|
since RubyX produces programs as it's output (which should run correctly), we need
|
||||||
|
to know doubly well that everything works. Both the RubyX code, and the generated code,
|
||||||
|
must work, ie be tested. Some may call this TDD extreme, i call it common sense, and
|
||||||
|
find it is the best way to work.
|
||||||
|
|
||||||
|
Specifically RubyX uses minitest, and has several layers of tests under the test
|
||||||
|
directory. Generally speaking, test files contain ruby code called tests.
|
||||||
|
This code exercises the source code and asserts (tests)
|
||||||
|
assumptions to be correct. Minitest provides a base Test class to derive from and
|
||||||
|
about ten different assert methods to assert assumptions. Methods of the class must
|
||||||
|
start with test_ and each such method is called a test.
|
||||||
|
|
||||||
|
RubyX currently has over 1700 tests with almost 15000 assertions.
|
||||||
|
At about 7k lines of code, that is roughly 2 assertion for each line of code. this
|
||||||
|
should give you an idea how important testing is in RubyX.
|
||||||
|
|
||||||
|
## Automated testing (edit, save , autotest) or guard
|
||||||
|
|
||||||
|
Guard is a tool to run tests automatically. Similarly to bundler, Guard defines
|
||||||
|
a Guardfile to define which tests should be run, and a command-line tool (guard)
|
||||||
|
to run them automatically.
|
||||||
|
|
||||||
|
Basic tests mirror the same directory structure as the code in the test
|
||||||
|
directory. Basic (or unit) tests live in files with the same name as the source
|
||||||
|
code file name, with a "test_" prefix, in a shadowed directory. Eg for a file
|
||||||
|
/lib/parfait/word.rb , there will be a file in /test/parfait/test_word.rb .
|
||||||
|
|
||||||
|
The Guardfile defines conventions like this, in code. So there
|
||||||
|
is a basic rule in the Guardfile stating that when a source file changes
|
||||||
|
the equivalent test file should be run. Other rules may be added easily,
|
||||||
|
as a Guardfile is really just ruby code, working against the guard api.
|
||||||
|
|
||||||
|
The way to use guard is to have a terminal open and start the guard command.
|
||||||
|
Guard will listen for changes, and once a file is saved *automatically* run
|
||||||
|
affected test files.
|
||||||
|
|
||||||
|
This way we're back to edit, save, the shortest possible loop. Only when all tests
|
||||||
|
are green, and there are enough (new) tests to cover the code, can you move on to the
|
||||||
|
next phase, sharing your code.
|
||||||
|
|
||||||
|
# Contribution process
|
||||||
|
|
||||||
|
Open source is all about sharing code. It maybe for the greater good, or just fun,
|
||||||
|
but it is working together in a coordinated fashion. Git (with commit rights) is
|
||||||
|
what makes the coordination easy, some might say possible.
|
||||||
|
|
||||||
|
You start with a clean environment, either you just cloned, or pulled from github.
|
||||||
|
|
||||||
|
There are several ways to find what you want to work on, but all roads lead to
|
||||||
|
github issue. You either find an existing one, or create one. Don't start
|
||||||
|
work on something that has no issue, and the best way is to make your intention
|
||||||
|
clear, by commenting on the issue.
|
||||||
|
|
||||||
|
## Topic branches and issues
|
||||||
|
|
||||||
|
Once you have a topic (and a github issue to go with it) you want to start coding.
|
||||||
|
But don' just yet. To manage you changes with others, it is best to create what is called a topic branch. Branches are very cheap in git (very little resources required),
|
||||||
|
and make it so much easier to manage the code. It is really not advisable to
|
||||||
|
skip this step (read: your contribution may not be accepted, which really is in
|
||||||
|
no-ones interest, least your own) unless it is a tiny, non-controversial change
|
||||||
|
like a typo.
|
||||||
|
|
||||||
|
git checkout -b 65_my_bugfix
|
||||||
|
|
||||||
|
This is the command to start a new (topic) branch. You'll want to start with the
|
||||||
|
github issue number and add a short description for the task.
|
||||||
|
|
||||||
|
## work on the issue / branch
|
||||||
|
|
||||||
|
As described above, you can now edit the code and tests to work on the issue.
|
||||||
|
You may use the github issue for discussion or help. You can also push the branch
|
||||||
|
to github and collaborate on the code. Or have someone review it.
|
||||||
|
|
||||||
|
Use guard, write minitests, edit (according to code guidelines) until happy.
|
||||||
|
Commit, push and create a pull request.
|
||||||
|
|
||||||
|
## about committing
|
||||||
|
|
||||||
|
Regular small commits make for the best workflow. Where the line goes is a little
|
||||||
|
bit experience, but often it is no more than 5 affected files, no more than 50-60
|
||||||
|
lines affected. For a professional, 1-4 hours, for a beginner more.
|
||||||
|
|
||||||
|
Commits should be grouped around topics. Ideally (but not always) a commit takes the
|
||||||
|
whole project back to green (all tests working). But this is not always possible
|
||||||
|
and should not keep you from making commits. Commit when you have made some kind
|
||||||
|
of milestone, some small but cohesive change.
|
||||||
|
|
||||||
|
Usually beginners tend to make to large commits, but just to mention that there is also
|
||||||
|
a lower limit. Technical a single line may be a commit, but it would have to be a very,
|
||||||
|
possibly very very important line. Ie a critical fix, a version update know to break
|
||||||
|
things.
|
||||||
|
|
||||||
|
Usually i don't commit changes under 10 lines. If they happen, i band them together
|
||||||
|
with the next commit, possibly mention them in the (then multi-line) commit message.
|
||||||
|
|
||||||
|
About commit messages, they should describe the change in passive mode, as if the
|
||||||
|
commit made the changes. Ie "Fixes bug 36" , or "Adds method XXX to YY"
|
||||||
|
|
||||||
|
## pull request
|
||||||
|
|
||||||
|
A pull request is you asking the project owner (or anyone with commit rights) to
|
||||||
|
accept your work and merge it into the main (master) branch.
|
||||||
|
|
||||||
|
For small issues and especially when it has been discussed, this is a press of a button
|
||||||
|
for the project owner. But for larger changes, he/she may want to pull the
|
||||||
|
branch to their machine, look at it and consider.
|
||||||
|
|
||||||
|
If there are changes to be made, more discussion may follow. This may result in
|
||||||
|
you having to make more changes and so the process continues. This is why topic
|
||||||
|
branches are so important, to keep this kind of back and forth out of the main
|
||||||
|
branch and maintain a working / clean master branch.
|
||||||
|
|
||||||
|
After a pull request has been accepted, you go back to the master branch, pull
|
||||||
|
changes, and start again with a new topic. And so life for the developer continues :-)
|
50
CodeStyle.md
50
CodeStyle.md
@ -14,6 +14,41 @@ While ruby allows the omission of brackets even with arguments, i try to avoid t
|
|||||||
of readability. There may be an exception for an assignment, a single call with a single arg.
|
of readability. There may be an exception for an assignment, a single call with a single arg.
|
||||||
Brackets without arguments look funny though.
|
Brackets without arguments look funny though.
|
||||||
|
|
||||||
|
### Method length
|
||||||
|
|
||||||
|
Methods should not be more than 10 lines long. It points to bad design if they are,
|
||||||
|
spaghetti code, lack of abstraction and delegation. This may seem extreme coming from
|
||||||
|
other languages, and i admit it took me some years to see the light, but now it's pretty
|
||||||
|
much that. Longer methods will have a very very hard time to get accepted in a pull
|
||||||
|
request.
|
||||||
|
|
||||||
|
### No of arguments
|
||||||
|
|
||||||
|
Methods taking over 4 arguments are dubious. Actually 4 is already borderline. If a
|
||||||
|
method actually needs that much info, it is most likely that a class should be
|
||||||
|
created to hold some of it.
|
||||||
|
|
||||||
|
### Class length and size
|
||||||
|
|
||||||
|
On class length i am not rigid, but too large is a definitely a thing. More than 5-6
|
||||||
|
instance variables probably means the class is doing too much and should be split.
|
||||||
|
Also a total loc of more than 200-250 or method count over 20 is not a good sign.
|
||||||
|
Especially when combined with struct classes that just hold data and have too little
|
||||||
|
functionality, this may represent problems in pull request.
|
||||||
|
|
||||||
|
### Global and class variables
|
||||||
|
|
||||||
|
Global variables is one of the few design mistakes in ruby. They just should not exist,
|
||||||
|
meaning they should not be used.
|
||||||
|
|
||||||
|
Use class variables only if you are sure you understand their scoping, specifically the
|
||||||
|
difference between class variables and class instance variables. Lean towards
|
||||||
|
class instance variables.
|
||||||
|
|
||||||
|
Since classes (and thus modules) are global, class and module methods are global.
|
||||||
|
Use sparingly with good insight, as it ties the usage to the definition and
|
||||||
|
oo benefits like inheritance are lost.
|
||||||
|
|
||||||
## Code style
|
## Code style
|
||||||
|
|
||||||
### Module functions are global
|
### Module functions are global
|
||||||
@ -21,8 +56,8 @@ Brackets without arguments look funny though.
|
|||||||
Often one thinks so much in classes that classes get what are basically global functions.
|
Often one thinks so much in classes that classes get what are basically global functions.
|
||||||
Global functions are usually meant for a module, so module scope is fitting.
|
Global functions are usually meant for a module, so module scope is fitting.
|
||||||
|
|
||||||
A perfect example are singleton accessors. These are often found clumsily on the classes but
|
A perfect example are singleton accessors. These are often found clumsily on the classes
|
||||||
the code reads much nicer when they are on the module.
|
but the code reads much nicer when they are on the module.
|
||||||
|
|
||||||
### Code generators
|
### Code generators
|
||||||
|
|
||||||
@ -31,3 +66,14 @@ All names are resolved to registers, or index via Type. More readable code less
|
|||||||
As the example shows, in this case the module function name should be the instruction class name.
|
As the example shows, in this case the module function name should be the instruction class name.
|
||||||
|
|
||||||
Singletons should hang off the module (not the class), eg Parfait.object_space
|
Singletons should hang off the module (not the class), eg Parfait.object_space
|
||||||
|
|
||||||
|
## Naming
|
||||||
|
|
||||||
|
Naming must be one of the most important and difficult things in programming.
|
||||||
|
Spend some time to find good, descriptive names.
|
||||||
|
In the days of auto-complete, short cryptic names are not acceptable any more.
|
||||||
|
|
||||||
|
When naming, remember to name what something does (or is), not how. A classic misnomer
|
||||||
|
is the ruby Hash, which tells us how it is implemented (ie by hashing), but not it's
|
||||||
|
function. In Smalltalk this was called a Dictionary, which is tells us what it's for,
|
||||||
|
to look something up (with real-world reference, double points).
|
||||||
|
24
README.md
24
README.md
@ -14,12 +14,12 @@ of the system, see below. The overhaul is done and rubyx produces working binari
|
|||||||
|
|
||||||
Processing goes through layers: Ruby --> Sol --> SlotMachine --> Risc --> Arm --> binary .
|
Processing goes through layers: Ruby --> Sol --> SlotMachine --> Risc --> Arm --> binary .
|
||||||
|
|
||||||
Currently most basic constructs work to some (usable) degree, ie if, while,
|
Currently most basic constructs work to some usable degree, ie if, while,
|
||||||
assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those
|
assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those
|
||||||
that ruby passes implicitly also work (lambdas not).
|
that ruby passes implicitly also work (lambdas not).
|
||||||
|
|
||||||
Work continues on memory management, which turns out to be pretty basic to do just about
|
Work continues on memory management, which turns out to be pretty basic
|
||||||
anything, even counting to a million.
|
to do just about anything, even counting.
|
||||||
|
|
||||||
## Layers
|
## Layers
|
||||||
|
|
||||||
@ -83,26 +83,24 @@ Generating code (by descending above layers) is only half the story in an oo sys
|
|||||||
The other half is classes, types, constant objects and a minimal run-time. This is
|
The other half is classes, types, constant objects and a minimal run-time. This is
|
||||||
what is Parfait is.
|
what is Parfait is.
|
||||||
|
|
||||||
Parfait has basic clases like string/array/hash, and also anything that is really needed
|
Parfait has basic classes like string/array/hash, and also anything that is really needed
|
||||||
to express code, ie Class/Type/Method/Block.
|
to express code, ie Class/Type/Method/Block.
|
||||||
|
|
||||||
Parfait is used at compile time, and the objects get serialised into the executable to
|
Parfait is used at compile time, and the objects get serialised into the executable to
|
||||||
make up, or make up the executable, and are thus available at run time. Currently the
|
make up, or make up the executable, and are thus available at run time. Currently the
|
||||||
methods are not parsed yet, so do not exist at runtime yet.
|
methods are not parsed yet, so do not exist at runtime yet.
|
||||||
|
|
||||||
### Builtin
|
### Macros
|
||||||
|
|
||||||
There are a small number of methods that can not be coded in ruby. For example an
|
There are a small number of methods that can not be coded in ruby. For example an
|
||||||
integer addition, or a instance variable access. These methods exists in any compiler,
|
integer addition, or a instance variable access. These methods exists in any compiler,
|
||||||
and are called builtin here.
|
and are called macros here.
|
||||||
|
|
||||||
Builtin methods are coded at the risc level with a dsl. Even though basically assembler,
|
Macros are coded at the slot_machine level with a dsl. Even though basically assembler,
|
||||||
they are
|
they are
|
||||||
([quite readable](https://github.com/ruby-x/rubyx/blob/2f07cc34f3f56c72d05c7d822f40fa6c15fd6a08/lib/risc/builtin/object.rb#L48))
|
([quite readable](https://github.com/ruby-x/rubyx/blob/2f07cc34f3f56c72d05c7d822f40fa6c15fd6a08/lib/risc/builtin/object.rb#L48))
|
||||||
through the ruby magic.
|
through the ruby magic.
|
||||||
|
The Macros are found in lib/slot_machine/macro .
|
||||||
I am in the process of converting builtin to a simple language on top of SlotMachine,
|
|
||||||
which i'm calling SlotLanguage. But this is wip.
|
|
||||||
|
|
||||||
## Types and classes, static vs dynamic
|
## Types and classes, static vs dynamic
|
||||||
|
|
||||||
@ -145,6 +143,7 @@ commands that have a linux baked in, qemu-arm in case of arm. So running
|
|||||||
machine where qemu is installed with *qemu-arm ./hello* .
|
machine where qemu is installed with *qemu-arm ./hello* .
|
||||||
|
|
||||||
On my fedora, the package to install is "qemu", quite possible on mac with homebew, too.
|
On my fedora, the package to install is "qemu", quite possible on mac with homebew, too.
|
||||||
|
The web-page has some more [info](http://ruby-x.org/arm/qemu.html).
|
||||||
|
|
||||||
### Interpreter
|
### Interpreter
|
||||||
|
|
||||||
@ -161,7 +160,7 @@ out what is going on, and in finding bugs.
|
|||||||
|
|
||||||
The above architecture is implemented. At the top level the RubyXCompiler works
|
The above architecture is implemented. At the top level the RubyXCompiler works
|
||||||
pretty much as you'd expect, by falling down the layers. And when it get's
|
pretty much as you'd expect, by falling down the layers. And when it get's
|
||||||
to the Risc layer it slots the builtin in there as if is were just normal code.
|
to the Slot layer it slots the macros in there as if is were just normal code.
|
||||||
|
|
||||||
Specifically here is a list of what works:
|
Specifically here is a list of what works:
|
||||||
- if (with or without else)
|
- if (with or without else)
|
||||||
@ -175,7 +174,8 @@ Specifically here is a list of what works:
|
|||||||
|
|
||||||
## Contributing to rubyx
|
## Contributing to rubyx
|
||||||
|
|
||||||
Probably best to talk to me, if it's not a typo or so.
|
Probably best to talk to me, if it's not a typo or so. For beginners i have written a
|
||||||
|
[BeginnersGuide](./BeginnersGuide.md) to start from zero.
|
||||||
|
|
||||||
I've started to put some github issues out, some basic some not so. Also there is a todo
|
I've started to put some github issues out, some basic some not so. Also there is a todo
|
||||||
for the adventurous (bigger things, no BIG things).
|
for the adventurous (bigger things, no BIG things).
|
||||||
|
Loading…
Reference in New Issue
Block a user