Not a tame lion...
Join Date: May 2004
Location: Narnia
|
The reason we program in an OO syntax is to facilitate code reuse, modularity, readability, and maintainability. It also allows our programs to be structured in a way that is easily describable and replicable, so the wheel doesn't need to be reinvented for every problem.
I say facilitate because all computer languages when reduced to machine code are in fact linear. To say a language really is OO even if its syntax looks like a shell script might be technically correct depending on the language (I too know nothing about ruby), but completely misses the point of OO. |
quote |
‽
|
Quote:
Quote:
None of these have to do with OOP. Quote:
|
|||
quote |
Not a tame lion...
Join Date: May 2004
Location: Narnia
|
Quote:
I thought I had said "why" in the first paragraph, but I'll give it another try. From the computers perspective, all programs are linear. They start at 10 START and finish at 100 FINISH. The computer doesn't care whether it is object oriented or if you wrote the program in ruby, java, or c, because it never sees that. So what is a programming language exactly? It is a language readable by humans for talking to machines. And because we are humans, we have further typed and subdivided these languages into other categories and given them labels. Object oriented is one such label. Without going into what Object oriented programming is (as that was covered in another thread) I want to explain why we use it. -It's easier to read. By giving classes and their methods meaningful names we have a much better idea what they are for. -It's easier to reuse. A collection of data and functions to manipulate that data and other data are encapsulated into a class. This class can then be used in any program without even looking at the code if documentation is provided. -It's easier to maintain. Because classes are separate from each other, you can easily make changes to one class without affecting the rest of the program. -It allows programmers to visulize programs and properly label specific computing problems that occur frequently. Because of this communication we have been able to identify said problems and come up with solutions for them so that each programmer who encounters the problem will not have to rethink the problem. In other words, it has made it easier for programmers to talk about their programs. You'll notice that all those reasons specifically have to do with programmers. Computers don't care about any of them. So OO is a human concept created by humans for humans. Allow me to reiterate my earlier comment. Quote:
So whilst a language may check all the blocks and meet the requirements for being calling OO. If it doesn't confer the advantages of being OO then what is the point? It's just a label. For example, the base object. If a method is automatically added to the "base" object how is this object oriented? Well by mechanical definition it might very well be, the interpreter has instantiated a base object in memory and added a method pointer to it's method index that may now be called by other subroutines. But has it made it easier to read, easier to reuse, easier to maintain, or easier to talk about? A machine might call it OO because it meets the definition but in my eyes it falls short, OO was created for me, not machines. In the same way human language shapes thought processes, programming languages shape computer programs. In my eyes a "proper" OO language facilitates the creation of proper OO programs through its structure and syntax. |
||
quote |
‽
|
Quote:
Quote:
As you state yourself, it's all about human choice. Certain things may be easier to do in a non-OO context. So this is your only concern? That messages can be sent outside an explicit object? You made a very long post if you only had one single point. |
||
quote |
Not a tame lion...
Join Date: May 2004
Location: Narnia
|
My smaller post was geared towards the Ruby is an OO language discussion, and my larger post was to explain "why" because you stated that I failed to explain why.
Basically my point is that OO code should look OO. If it doesn't look OO even if it is technically, then of what use is it? I personally have no concern, I'll learn and use Ruby if I'm ever in a situation where it would be advantageous to do so. Last edited by AsLan^ : 2006-04-17 at 04:48. |
quote |
‽
|
I strongly disagree with a notion that a language should limit its user's freedom for the purpose of "cleanness". Python, for example, enforces a certain typography, if I'm not mistaken, something I simply can't live with. A computer should give me the freedom to operate in the way I want to.
Take HTML: you can have a page that is well-formed and validates, yet it can be semantical nonsense. It's up to the author to fix that, not to the language. Likewise, Ruby doesn't force me to write clean OOP. It doesn't keep me from doing so either, but it doesn't insult me with "I don't like your code". That's not its job. That's the job of human peers. |
quote |
Veteran Member
|
Hey chucker just noticed this on digg..
I don't know if you frequent digg or not but it seems like quite a nice little blog entry with loads of resources on Ruby.. http://ibloggedthis.com/2006/04/16/r...inks-and-more/ Enjoy. 'Remember, measure life by the moments that take your breath away, not by how many breaths you take' Extreme Sports Cafe | ESC's blog | scratt's blog | @thescratt |
quote |
‽
|
Quote:
(It would be interesting, of course, if one and the same codebase could 'power' a CLI app, a GUI app and a web app. Thanks anyways. I've made some significant progress on my code and I suppose I could publish it here again; I'd be delighted to hear what parts of it need to be more OOP |
|
quote |
‽
|
Code:
#!/usr/bin/env ruby
require 'socket'
require 'iconv' # conversion between native and Windows-1252
# constants: some of these should eventually be moved inside explicit objects;
# others are just fine this way an dothers again (e.g. DefaultHost) will
# eventually fit inside a settings mechanism
Version = "1.0d7"
ProtocolVersion = "1"
DefaultHost = 'cho.cyan.com'
DefaultPort = 1812
DebugPort = 1813
C2SLoginCommandID = 10
C2SQuitCommandID = 15
C2SPrivateMessageCommandID = 20
C2SRoomMessageCommandID = 30
C2SWelcomeCommandID = 40
C2SIgnoreCommandID = 70
S2CNickErrCommandID = 10
S2CNickSetCommandID = 11
S2CPrivateMessageCommandID = 21
S2CRoomMessageCommandID = 31
S2CWhoListCommandID = 35
S2CWelcomeCommandID = 40
S2CIgnoreCommandID = 70
# as specified by RFC 822: http://www.ietf.org/rfc/rfc0822.txt
CommandTerminator = "\r\n"
NativeEncoding = 'utf-8' # assume the system you're running CCCCCCC on isn't from the past
CyanChatEncoding = 'windows-1252'
GroupUser = 0
GroupCyan = 1
GroupServer = 2
GroupGuest = 4
# These will go away once we have a settings mechanism
Timestamps = 1
RotateLines = 1
Nickname = "cccccccTest"
# String mixins
class String
# add string conversion for CC's backwards-ish windows-1252
def nativeToCCEncoding
begin
iconv = Iconv.new(CyanChatEncoding, NativeEncoding)
convertedText = iconv.iconv(self)
rescue Iconv::IllegalSequence
# TODO: return some decently converted string
puts "faulty nick"
convertedText = "faulty nick"
rescue Iconv::InvalidCharacter
puts "even worse nick"
convertedText = "even worse nick"
end
end
def ccToNativeEncoding
begin
convertedText = Iconv.new(NativeEncoding, CyanChatEncoding).iconv(self)
rescue Iconv::IllegalSequence
puts "faulty nick"
convertedText = "faulty nick"
rescue Iconv::InvalidCharacter
puts "even worse nick"
convertedText = "even worse nick"
end
end
def cleanupNickname # meet server's criteria for the nickname length and text
# nicks must be at least 2 characters, so let's add an invisible character: a non-breaking space
newNick = self
if newNick.length < 2
newNick += ' '.nativeToCCEncoding
end
# delete forbidden characters from nickname
forbiddenCharacters = []
[',','.','|','^'].each do |character|
if newNick.include?(character)
forbiddenCharacters += [character]
newNick.delete!(character)
end
end
# notify the user of the character(s) at fault
if forbiddenCharacters.length > 1
print "Please note that the following forbidden characters were found in your nickname and removed: "
else
print "Please note that the following forbidden character was found in your nickname and removed: "
end
forbiddenCharacters.each do |character|
print character + " "
end
puts # trailing newline
return newNick
end
end
# a class representing a command
class CyanChatCommand
def initialize(commandID, arguments)
@commandID = commandID
@arguments = arguments
end
# creates a command from the given line
def CyanChatCommand.createCommandFromLine(line)
if line.length > 3 && line[2].chr == '|' # if command includes arguments
parts = line.split('|', 2)
commandid = parts[0]
arguments = parts[1] # this will need further splitting into arguments, in /other/ methods
else # command has no arguments
commandid = line
end
return CyanChatCommand.new(commandid, arguments)
end
def CyanChatCommand.createLoginCommand(nick)
nick.cleanupNickname
# create login command
CyanChatCommand.new(C2SLoginCommandID, nick.nativeToCCEncoding)
end
def CyanChatCommand.createQuitCommand
CyanChatCommand.new(C2SQuitCommandID, nil)
# e.g.: C2SQuitCommandID + "\r\n"
end
def CyanChatCommand.createWelcomeCommand
CyanChatCommand.new(C2SWelcomeCommandID, ProtocolVersion)
# e.g.: C2SWelcome.to_s + "|" + ProtocolVersion + "\r\n"
end
# returns a binary representation of the command, ready to send
def serialize
# append command id
bytes = @commandID.to_s
# append arguments
if @arguments
bytes += "|" + @arguments
end
# append terminator
bytes += CommandTerminator
return bytes
end
# return a debug string
def to_s
return "DEBUG " + Time.now.strftime('%X ') + output + "\n"
end
end
# connection class
# manages the TCP connection to the CyanChat server
class CyanChatConnection
attr_accessor(:tcpSocket)
def initialize(host=DefaultHost, port=DefaultPort)
@tcpSocket = TCPSocket.new(host, port)
@bufferLines = []
end
def sendCommand(command)
@tcpSocket.send(command.serialize, 0)
end
# read next line from connection
def readNextLine
# no buffered lines left: read more
if @bufferLines.length < 1
buffer = @tcpSocket.recv(1024)
@bufferLines = buffer.split(/\r\n/)
end
# return first line and delete it
return @bufferLines.delete_at(0)
end
def connected?
# FIXME: check whether socket is still open
return true
end
# return a debug string
def to_s
# make timestamp
debug = "DEBUG " + Time.now.strftime('%X ') + "\n"
# append all buffered lines
bufferLines.each do |line|
debug += " " + line.ccToNativeEncoding + "\n"
end
return debug # TODO: test if this works'
# previously:
# return "DEBUG " + Time.now.strftime('%X ') + "\n" + bufferLines
end
end
# main class
class CyanChatClient
def initialize
@connection = CyanChatConnection.new(DefaultHost, DebugPort)
end
def run
# send welcome command
@connection.sendCommand(CyanChatCommand.createWelcomeCommand)
# run loop which reads and reads and reads
while @connection.connected?
# select socket or keyboard input
activeIO = select([$stdin, @connection.tcpSocket])
# handle next line from socket or keyboard
if activeIO.to_s.eql?(@connection.tcpSocket.to_s)
handleSocketData(@connection.readNextLine)
elsif activeIO.to_s.eql?($stdin.to_s)
handleKeyboardData($stdin.gets)
end
end
end
def handleSocketData(line)
puts "### [SOCK] " + line
# convert it into a command object
command = CyanChatCommand.createCommandFromLine(line)
# handle command... somehow
# TODO: handle command
end
def handleKeyboardData(line)
puts "### [KBD ] " + line
case line
when /\/login[\n\r]?$/
puts "=== Logging in!"
@connection.sendCommand(CyanChatCommand.createLoginCommand(Nickname))
when /\/quit[\n\r]?$/
puts "=== Quitting!"
@connection.sendCommand(CyanChatCommand.createQuitCommand)
end
end
end
# main program
cyanChatClient = CyanChatClient.new
cyanChatClient.run |
quote |
Not a tame lion...
Join Date: May 2004
Location: Narnia
|
I actually installed Ruby to try this out
You might want to include a "download" link because to cut and paste I first had to pretend like I was going to quote you and then cut the text from the resultant text box otherwise it stripped out all the carriage returns. Perhaps its just a Firefox or Linux thing. Anyway I like the way you've rearranged your code, although I'm still curious if it's possible to split the classes into separate files. |
quote |
‽
|
Quote:
In any case, here you go. Slightly newer version too, and I've included some of the remains of the pre-OOPization code. Quote:
I can try and put the CCCommand and CCConnection classes in their own files; give me a few. Last edited by chucker : 2006-04-18 at 09:20. |
||
quote |
‽
|
Tarball containing a three-part version of the same code. All I did was split off CyanChatCommand and CyanChatConnection into their own files, core/cccommand.rb and core/ccconnection.rb, then add require statements in main.rb to include them.
Notice that 'require' adds the '.rb' extension to the search path automatically, so I could omit it from the require statements. |
quote |
‽
|
Alright, so, as detailed in my blog, I'm running into a Windows socket handling problem. Specifically, my select() call that switches between keyboard input and TCP socket input doesn't work, as Windows never switches to the latter (or rather, the bug is supposedly, that Windows never stops listening on the keyboard).
Various searches and inquiries on the web, on #ruby-talk, etc. yielded very little useful information.
So that basically leaves me with the routes of moving to threads or moving to non-blocking sockets. However, I have found extremely little information about either. Communicating between various objects of one thread to another doesn't seem all that easy, and while non-blocking sockets apparently get activated by using a special parameter, I haven't really gotten that to work yet either. Worst of all, even with removing the select() call, not accepting keyboard input at all and concentrating on the network socket for now, the app behaves confusingly under Windows. It receives one batch of socket data, then hangs. There's no backtrace either. On the bright side, I have written a nice little class for storing and retrieving settings using YAML. Would be even nicer, perhaps, if I could extend it to use the Windows registry or plists on OS X, but this solution works fine for now, on OS X, Linux and Windows. Here it is. |
quote |
‽
|
Actually, scrap all that, I apparently found a solution, namely an exemption in Cygwin's license.
Quote:
|
|
quote |
Posting Rules | Navigation |
|
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Microsoft forced to (kind of) open XP source code... | Wyatt | General Discussion | 4 | 2006-01-25 11:17 |
Prettier HTML Source Code | drewprops | Programmer's Nook | 5 | 2005-12-20 00:36 |
Result Code in Toast 6.1 | pilot1129 | Genius Bar | 6 | 2005-07-21 23:29 |
Microsoft code garbage? | alexluft | Third-Party Products | 10 | 2005-04-28 10:05 |
10.3.6 Available in Software Update | Moogs | Apple Products | 86 | 2004-11-20 15:12 |