Ruby Scripting
#1
Quote:This topic is about Ruby Ruby itself and perhaps it might contain some gaming aspects every so often. Even so I don't mind if you take a look at previous posts regarding RGSS and its quirks.

Ruby Scripting

What's Ruby Ruby?

It's a programming language. Originally it was just object oriented thus it has been great for OOP.

Did you ever hear the term "spaghetti code"?

It's a derogatory term for messy code and some people apply it to OOP languages whenever they wanna criticize them for making objects out of everything. Ruby is no exception. In version 1.8.x its base class was Object, since 1.9.x or 2.0.x it's been BasicObject. So yeah, everything is an object in Ruby (and RGSS and Gosu and so on).

Is it Ruby's fault to be a messy bunch of code?

Nope, it isn't. It's a scripter's fault actually. Your coding style will determine if you're able to become a scripter or programmer, not the language. You can pick any programming language that suits your needs or your business's but it's up to you to make something useful out of it. If you're bad in programming in C or C++, you can making a mess of a program as well.

Is Ruby slow?

Well, Ruby version 1.8.x was no roadrunner for sure but it was decent for small or medium size projects. 1.9.x offered us some improvement, still, the 2.x series are something to take into account for it's becoming faster and faster. 2.6.x even allowed us to experiment with MJIT, Ruby's version of JIT, by memoizing method calls while running scripts.

Even so Ruby's been fast parsing text files. Rubygems allow Ruby to even deal with complex stuff like XML as well.

Why should I pick Ruby?

Again, that's up to you. Making the decision of making "small" games or Ruby on Rails / Sinatra apps, depends entirely upon your shoulders. Since we're on a forum dedicated to game making I'll assume you're interested in OOP and Ruby and you'll continue reading a series of post concerning this interesting topic.

The Basics

I'm a lazy scripter Laughing  so I don't expect me to apologize if I don't go into specific details here and there. I'm not interested in getting feedback nor criticism for I'm doing this for free. If you don't like this guide, that's your sole problem. Go find another one. Laughing + Tongue sticking out

Object Class


Since it's the main class in Ruby, fine, it was till BasicObject showed up, I'm gonna tell you about it. Whenever you run a script in a terminal window alias console or DOS depending on your Operating System, you're asking Object to deal with pretty much everything you've got to type or run there. Unless you create classes and modules, you're just dealing with the Object class.

Object runs a main method, namely "main". If we compare this with ye old RM scripts, it's the most basic main method ever. Without it Ruby wouldn't run not even for a second.

Does this mean that we need to create main methods in non RM scripts?

Nope. Don't even try that! That's something that the RM series introduced to their niche, cultist group of emerging game developers. How you run your games or scripts depends on where you wanna run them. A Ruby on Rails or Sinatra web app would use something entirely different, I can guarantee you they have nothing in common with RM.

How do I use the Object class?
Sarcasm Seriously? Well, you haven't been paying attention here then. I told you everything you don't create in classes and modules are objects, thus are part of the Object class. So something like:

puts "Hello SavePoint!"

...was run as part of the Object class. (Even if puts actually belongs to the Kernel module...)

What's that Kernel module you've mentioned here?

Happy with a sweat OK, let me find a way to easily explain it. Kernel is an ubiquitous module, it's automatically added to EVERY single object as a way to provide them with methods like puts without specifying such methods' origin. It just keep it simple for you to call them anywhere at anytime. It's in charge of some other stuff as well, but this guide won't cover it. Fine, I'll make another exception here:

hash = Hash(:m => 1)
#=> { :m => 1 }

Here Kernel module created a hash object for you. As an exception Hash is another method of the Kernel. Usually methods should be defined in lowercase. Still its purpose is to keep it simple for YOU.

We better start discussing methods here. Happy with a sweat 

Methods

They are some of the basic contents of a class or module. If you ever need to define or modify some logic, use methods! Shocked They do exist to help you with that. You can call them like I did above by using puts or Hash. There are other ways to make them run.

my_concert = Concert.new
my_concert.start

...and a concert would be held somewhere and would begin once all assistants took their seats. (I'm guessing here. Confused )

There you could find a curious but important method for Classes. It's the new method. In Ruby and even in Crystal new initializes a copy of the Concert class.

Why would we ever do that?

That's because you don't expect to organize a single concert in human history, do you? Laughing

In Ruby you call methods by connecting them to an object, either a class or an object, by typing a dot in between. Rarely you'd see some weirdos using :: instead, but just don't copy their weird style. Laughing

There's something interesting about the new method you better learn about right now, you NEVER define it in scripts! You could only define it if you were working on a rubygem or Ruby extension if you really got some C programming skills to ever achieve such a goal.

"CRuby new method"

From the Ruby side you never define new but you still have some sort of "replacement" called initialize.

In Ruby you don't need to create an initialize method for modules since they should never be initialized anyway. Classes allow you to define it, but Ruby also provides you with a default initialize method in case you don't wanna create your own. Most people prefer to create their own initialize method anyway. Happy with a sweat 

initialize (called by CRuby rb_obj_call_init function) will be invoked by the new method which will pass its arguments down the line.

SIDE NOTE

Matz, Ruby's creator, didn't call initialize Ruby's constructor method in the original documentation he wrote many years ago that has been translated to English. Even so, people treat it as its constructor because it reminds them of C++ where a function with the class name will create the variables needed by the given class.

Why does new or initialize matter here?

Sarcasm I guess this was unavoidable... It's because you won't get a new copy of your class or anybody else's if you don't! By default you get just a single class, NilClass alias nil. That means it's not been initialized, constructed, created, defined, etc. It doesn't exist so far. Plus, you usually define custom values inside your initialize method. Try this!

value == 1
or
print value == 1

And you'd get either a false value in any version of RGSS or an error message telling you value has not been initialized and it doesn't even know if that's a method or a variable if using a later version of Ruby Ruby.

Why is that happening?

RGSS1 through RGSS3 DO allow you to use local variables without initializing them first.
The problem comes when you port them to mkxp or HiddenChest or other modern and open source projects that run RGSSx games. They always use later versions of Ruby that removed that behavior, breaking back compatibility for sure. Confused

Objects You Should NEVER Initialize

Those would be a few classes indeed. They're true, false, nil, numbers and modules, of course!

You'll get plenty of errors if you ever try to do that.

Ruby classes are always open so you can initialize them as many times as you wish (and especially add them whatever you wanna include there). OK, if the script is protected or it's close source, you're out of luck... up to a certain point.

You can still add stuff to them but it might not be linked to their original implementations because some of them might be coded in C or C++. Think about the Bitmap or Sprite class in RM series, they're good examples of what you can't completely modify unless you wanna mess with their built in functions and making them stop working out of the blue. Laughing Still, you can add a few things here and there. (Warning! Your Ruby additions might not be as fast as you'd expect them to be.)

Defining an initialize Method

Code:
class MyClass
  def initialize
    @some_variable = 0
    @some_boolean = false
  end
end

There it is! Shocked We have defined our very first class!

We told Ruby to create a class called MyClass that you can build at will and it will get 2 default values for 2 specific instance variables, namely @some_variable and @some_boolean. They'll keep holding 0 and false values as long as your copy of your class exists.

How did we define a class to contain our methods? By calling class and providing it with a class name that uses CamelCase. Well, it can just begin with a single capital letter and that would be good enough to create it. Laughing

Don't forget! Happy with a sweat Keep exploring the map! Shocked
I mean, end all methods and classes and modules with a final end to close them. Laughing  

But I can't do anything with it! I tried and got nothing!

Happy with a sweat That's true! We forgot to let our class modify those values at a certain point. Don't worry! We can define them now.

Code:
class MyClass
  def some_variable() @some_variable end
  def some_boolean() @some_boolean end
end

Why didn't you reuse the script posted above?

Laughing Because I told you I'm lazy! Plus all Ruby classes are open so I can extend them by defining new methods at will. Unless you were working on a script already, you can reopen that class as many times as needed. This has been quite common in the RM world where default script modifications reopened existing classes to alter their behavior or just add some new stuff.

Warning! Shocked

Don't mention the parent class there! There's no need for it! You only need to do that once!
Ruby Ruby has good long term memory, guys! Winking

Huh? I wasn't planning to do that. What's a parent class anyway?

Sarcasm Yeah, I had to keep blabbing... Well, it's a class that was predefined as the original class for your set of custom scripts. In pure Ruby the very first case would be BasicObject, it's Object's parent class. In RGSS there is no BasicObject class but just Object as the top class.

Code:
class BasicObject
end

class Object < BasicObject
end

We could basically say that's how they were defined in Ruby. Your classes would already become Object class's children by default. Even so you can define something else as a class's parent class. The catch would be it'd exist by the moment you create the child class. Hit your head against the wall if you haven't. Laughing Just kidding!

By the way those 2 methods I created a while ago are called getters in many languages. Why? Because you can only get their current value. Laughing + Tongue sticking out 

But Sad I wanna set their new values now! I need to!

You remind me of a certain dreamer... Confused Anyway, you can do that by creating another two methods.

Code:
class MyClass
  def some_variable=(new_value) @some_variable = new_value end
  def some_boolean=(new_value) @some_boolean = new_value end
end

That's all you need to do to create their setters!

Shocked Wow!

Really? ? Actually I should have told you before there are other ways to create the same methods with less typing. Laughing 

You're a mean scripter for sure! Shocked 

Really? ? Am I? Confused Anyway, here's how you can do it fast enough for those impatient visitors we got tonight.

Code:
class MyClass
   attr_reader :some_variable, :some_boolean
   attr_writer :some_variable, :some_boolean
   attr_accessor :some_variable, :some_boolean
end

Nothing? Really? ? No reaction coming from you now?

Nope, got nothing to say. Confused

O_O Well, before I leave to grab some snack, I'll tell you something valuable. The first attr_ calls creates the methods for us, attr_reader is a method to create the first two methods you've seen above. attr_writer creates the last two of them.

But there's a third one there! I have spotted it already! Shocked 

Yeah, my desperate detective Detective in training, Sarcasm there's a third call, attr_accessor that actually creates both kind of methods, setters and getters. Laughing 

I told you that you were really mean! Shocked 

Excuse me for saving it for the very last moment you'd need to pay attention to my blabbing. Laughing

Happy Game Scripting Full Testing of Lag! Laughing  
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#2
More About Parent Classes

Tonight I guess I should tell you a bit more about parent classes and why you need them.

Do you really need them?

Happy with a sweat As I told you before, or at least I should have done so back then, that depends on your very personal design. Some people never use them while others do on a daily basis. So you're gonna learn when you should use them or just skip them if there's no use in creating them in the first place.

Code:
class Rect
  def initialize(x, y, w, h)
    @x = x
    @y = y
    @width = w
    @height = h
  end
  attr_accessor :x, :y, :width, :height
end

Do you see that? It's our basic Rect(angle) class! Shocked 

Sarcasm So what?

Really? ? We finally created a working class! That's why it matters a lot! Now tell me if you do feel you need a subclass or parent class of it.

Confused How should I know? You're the one that picked this specific topic!

Right... Sarcasm + Confused If you ever feel like that, probably you won't need either of them. Laughing
Yeah, you could later come up with other classes like other shapes, namely Circle, Triangle, and so on. Honestly you can stick to rectangles only for most of your gaming needs. At the end, you won't deal with any other geometrical shape unless you start using something like OpenGL and start depending on your graphics cards capabilities. Laughing + Tongue sticking out 

So how do you know when to subclass some bunch of code? Here's when you should do that!

Code:
class Person
  def initialize(name)
    @name = name
    @age = 0
    @ssid = "0"
    @job = ""
    @skin_color = Color.new(0,0,0)
    @eye_color = Color.new(0,0,0)
    @hair_color = Color.new(0,0,0)
    @hobbies = []
    @relatives = []
    @phone_number = ""
  end
  attr_accessor :name, :age, :ssid, :job, :skin_color, :eye_color, :hair_color, :phone_number
  attr_reader :hobbies, :relatives
end

Do you know every single person share stuff in common?

I guess so... Indifferent 

Well, that could later become our first parent class!

How so!? Shocked 

That's easy to explain! We know many people share traits like name, age, skin, eyes, hair, and so on. With this we can already create an object to represent a person like a student or coworker or site administrator or just some dreamer that complains about heat and many more!

So what's next? Grinning 

Really? Coming up next would be our first child class! Let's define one right away!

Code:
class Gamer < Person
  def initialize(name)
    super
    @played_games = []
    @favorite_games = []
    @despised_games = []
    @hours_spent_gaming = 0
  end
  attr_reader :played_games, :favorite_games, :despised_games
  attr_accessor :hours_spent_gaming
end

Shocked Wow! You defined a Gamer gamer as inferior, less valuable than an average person!

Yeah, I did! Laughing + Tongue sticking out But don't let that offend you in any way possible. I did that only for scripting purposes. For languages like Ruby anything that's related somehow to another basic class is "inferior" for a different reason. Actually it means it descends from a basic template called Person. Since a person isn't always a gamer, it's better to place Person first and Gamer as is direct subordinate. Nope, it's not his or her employee or servant, it's just a class that will call a Person's methods and add new ones that won't describe other persons but just gamers. I think it might be easy to understand if I show you another example now...

Go ahead! Grinning 

Sarcasm OK, this time we'll talk about lawyers!

Code:
class Lawyer < Person
  def initialize(name)
    super(name)
    @degree = ""
    @got_license = true
    @location = ""
    @workdays = []
    @customers = []
    @work_phone_number = ""
  end
  attr_accessor :degree, :got_license, :work_phone_number
  attr_reader :workdays, :customers
end

As you can see a lawyer, even if nobody likes them except for their own families Laughing also share common traits but got others as well. If we didn't have a Person as parent class, we would keep repeating code over and over again.

Shocked So you're teaching us how to become lazy as scripters!

Sad You make it sound as a bad thing...

Shocked But it is bad indeed!

Sarcasm Nope, it isn't. At least not in this case. Ruby's and any other OOP's goal is to let you reuse code by subclassing stuff as much as needed. This way you won't need to copy thousands of lines of code every single time you wanna add new features or change them. Plus, why on earth would a busy Lawyer care about videogames? He needs to prepare for his next trial after all. He'd probably hate you for thinking all lawyers and even Judge judges are like those found in Ace Attorney games. Laughing

Shocked Hey! I liked those games! They were quite realistic!

O_o? Are they!? Anyway, I've proven that we might need a basic parent class in case we might later define several descendants that will need to call stuff defined in the parent class. This pattern will save us from adding many checks in our code just to define when a person should turn on a TV set or open a briefcase or yell Objection! You wouldn't do that if you were just sitting on a seat like many other passengers while traveling on a bus or train or metro, would you!? Laughing + Tongue sticking out

Now we're gonna discuss what's super!

Batman Batman is super indeed! Shocked Many would say Clark Kent Superman is, but he's just a guy on steroids!

Really? ? Now we got somebody full of fleas that can't waste a chance to show off how he wasted his time reading comics. Laughing 

Actually for Ruby none of them would be super.

Shocked Say what!?

Yeah, none of them are, I do agree with Ruby on this. Laughing + Tongue sticking out The main idea behind it would be that both of them would be living beings so none of them could be called super or need to call super, the Ruby method. Laughing For Ruby super means "Hey! Go call my parent and see if he needs to get some new name!" Laughing Actually Gamer and Lawyer did yell at Ruby they were passing a name to Person. They both did the exact same thing but one of them was lazy as to explicitly pass it and let Person assume he would know what they were handing out to him. Or were they irresponsible enough as to let others blame their parent instead? Confused 

Code:
class Siletrea < WannabeDragonfly
  def initialize(name)
    @name = name
    @claws = []
    @age = 0
    @favorite_habitat = ""
  end
  attr_accessor :name, :age, :favorite_habitat
  attr_reader :claws
end

Wait a second! Shocked Why didn't you define Siletrea as another Person here?

Really? ? Is it my fault she believes she's a dragonfly? Laughing Plus she got claws, Confused and believes she can fly and attack poor people like me. Sad At the end she will fail to achieve her goal because she's a person and so our code will fail as well. Laughing You see, we never defined a WannabeDragonfly class before we defined her. Laughing + Tongue sticking out

By the way, just in case you include arrays or hashes in your classes, you'd usually need getters only. Most of the time you'd just change their contents, not the entire array or hash. Thus there's no need to define something you don't need. That will keep your code clean and won't ask for extra resources that are gonna get wasted anyway. Laughing 

How large can a class ever be?

Err, again, that depends on your project and coding style. Laughing + Tongue sticking out Usually you should only include what's enough to keep it running. Any extras should belong to specialized classes like subclasses alias child classes. There's no specific maximum size, but people say a large script takes longer to load than several short ones and the latter can let you find bugs in no time while the former might make it excessively complex for they might affect many lines of code at a single time. Confused The only way you can be certain if it's a good or bad idea might be to load a project and its backup and see if any of those gets affected by how large the scripts currently are. Still, for a few scripts that won't ever matter. For hundreds of them Confused I can't tell for sure it they will play along as a single, unified team. Happy with a sweat Even so new versions of Ruby might make it a bit harder to notice. Besides, non graphical scripts won't consume as many resources as those manipulating shapes or changing colors on the fly and so on. Laughing 

Warning!

Don't abuse of loops or you'll get stuck in no time! Shocked

Happy Stack Overflow! Laughing + Tongue sticking out  
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#3
Modules

What are modules in Ruby Ruby? If you come from a language like C++, you would say a module is a namespace.

What is that? Confused It is a container! Laughing

Yeah, the most basic explanation on modules would be that they contain stuff. I know, you are going to tell me now that classes also contain their own stuff. Confused The truth is that they do not need to be initialized like classes do in both languages. You could say they are floating in their own space.

Yeah, you could say that each module own its own boat and it keeps navigating the vast sea separated from all classes. It is not like it hates classes, it just can live and be invoked without them. Even so you can also mix them with classes in Ruby Ruby, something they have called a mixin. So yes, you can also use them as if they were an integral part of that specific class at will. Thus module ChipFlavors can be inserted in the Snack class to expand it by adding some sort of new toppings for all chips you can eat.

Code:
module ChipFlavors
 CHOCOLATE_CODE = 100
 MAYONNAISE_CODE = 101
 KETCHUP_CODE = 102
 MUSTARD_CODE = 103
 PEPPER_CODE = 104
end

class Snack
 include ChipFlavors
 def initialize
   @name = “”
   @price = 0
   @expire_date = “09-30-2019”
   @flavor = “”
 end
 attr_accessor :name, :price, :expire_date, :flavor
end

class Chips
 def initialize
  @name = “ChocoChips”
   @price = 2.50
   @flavor = “chocolate”
 end
end

We could add dozens of interesting chips recipes here but the point will remain the same. Our module, ChipFlavors, includes all chips flavor codes. This fact allows us to easily handle all of them in a single place without messing up with the actual classes that use them. Just imagine how tiresome it would become after a few years when we got like 50 different chips packages with different flavors.

Confused Checking every single of them would be harsh indeed. Centralizing some specific data makes it a bit easier to handle in a timely fashion today and even in the next couple of years. If we assigned one CONSTANT of all of them to every single class, we would probably take a long time to finish that process.

Actually for a machine it might be even better to just keep the module separate without mixing it in the Snack class. If you ever need to change codes, deprecate some and so on, you would only care about a module and not every single class every time you needed to update a vending machine.

Today we have learned three things. We got modules, mixins and one that was obviously different and still got pretty much ignored, CONSTANTS.

Ticked off Why do you keep yelling at me!?

O_o? I am not!

Shocked Yes, you are! Can’t you see all those capital letters?

Look Up Oh, those letters… Well, the thing is that I did that on purpose but with a different motivation. You see, they are called Constants and can be either be written like a Constant or CONSTANT. Actually, it IS a must to do that!

Ticked off Say what!? Now I need to keep yelling at other people?

Do not say that! We are not breaking some rule, we are following one indeed! You see, Ruby cares about how you type stuff on your computer. Use lowercase and it will treat that word or compound as either a variable or a method. Use @ at and it will think it is an instance variable. Type @@ and it will become a class variable. Still, if you use $ dollar symbol, it will not believe it is an amount but a global variable. Anything starting with an uppercase letter will be considered to be an actual Constant. It is part of what we call a programming language’s syntax. You could say it is like its own set of grammar and punctuation rules.

No matter if you respected your teachers at school or not, Ruby will force you to respect its rules! Go against what is common sense in the rubyist world and you will not get past that point ever. Laughing Really, it is a BAD idea! There are still some obscure ways to tweak its normal behavior, but no matter how good you think you are, DO NOT DO THAT! It is better to keep it as compatible with the default Ruby implementation as possible.

By the way, you mix in modules in classes by calling the include ModuleName right below that class name. You can include as many as deemed necessary.

Just keep this in mind, use CONSTANTS to permanently store data as long as your program is active. Do Not Change Their Contents after defining them! I mean, do not ever think you can do stuff like changing their contents one hundred lines of code later. If you defined them in a specific way, keep them like that for the rest of its execution.

Of course you can update it whenever you are maintaining its code while it is not running on any machine, but do it only then. If you just load it during its testing stage, it will not really matter. Just never do it while in its production stage (whenever you are already dealing with the “real world” audience).

Then why did you mix lowercase and uppercase?

O_O I did it because you can do so if you are defining a class or module. Use uppercase (and underscore once or twice) only if you are creating a class or module CONSTANT. I mean, when it belongs to that class or module.

I have seen people nesting classes and modules at will. Why’s that?

Err, well, you could say they are free to do so. For instance, you could define a single module and then lots of classes inside… like the RPG module in the maker series. Stuff like RPG::Actor and so on are a “living proof” of it. Double colon :: mean the connection there is between the container module and its inhabiting class. To be honest with you, you can do that with two different classes as well. There the difference would be that the first class might call the second class as some sort of helper class that might contain stuff you deliberately wanted to separate from the main class. RPG::Event and its subclasses are an excellent example here. The sections you can see in the event editor might belong to either the main or the secondary classes.

This is why I cannot stop repeating myself. Everything depends on your coding style at the end.

Is there anything else I might need to know about modules?

O_o? I am uncertain if you really need to know this, but Module is a class. Laughing + Tongue sticking out Yeah, even if it sounds weird, that is exactly what it is, just another Ruby class. What makes it important is that it does not ask you to initialize it and you can place it pretty much anywhere, and it keeps your code neat. For example, in my unreleased games KUnits and A Short Odyssey Gosu versions I keep language support stuff separated from scene classes to keep it easy to maintain. There I usually use the Lang or Terms module for such purposes. Yeah, there are many ways to deal with it but I just picked one of them because I felt like it. Laughing

Guess what? There is something else you might need to learn about them.

What is it?

Modules can contain more than just CONSTANTS. You can place floating methods there as well. That is not an official term, it just attempts to teach you they are not officially part of that module.

That’s impossible! You gotta be kidding me!!

O_o? Nope, I am not. The main idea behind it is that you should be able to do the same you have done with CONSTANTS as with any method you would like to include in one or more classes where you will include that module of yours.

So what happens to those methods after the mixin!?

They kind of become part of that class’s list of methods. Yeah, you could not distinguish them from the rest if you print the whole list! That is what makes them run smoothly as if they had always been there!

Are you saying modules will never own any methods ever!?

Err, nope, I never said so. There IS a way to make it own any specific method. You see, so far we have only seen that methods are called by typing the def keyword followed by some method_name. Normally that means that method will belong to a class. To change that in a module, we can add something special there. It is the self keyword!

Code:
module MyModule
 def self.method_name
   print “I belong to MyModule only!”
 end
end

Yes, it only belongs to that module now! In English it might be self evident what self actually means. For those speaking foreign languages (like your lazy servitor here), it might be strange to see how it is used. Honestly, it just means “I” or “me” own this method so call me first to access it properly. It is a simple replacement for that module’s name, meaning it will also work if you type that name instead. Since self is shorter and easy to understand, the convention is that you would just type self and not the module’s name there.

What if I’ve got plenty of module methods!?

Do not worry then! There is a simple way to avoid typing all those dozens of egotistic self.

Use module_function in a separate line and all methods written below will become module methods by default. Again, I told you Ruby Ruby lets you become lazy scripters. Laughing

Kyonides Wrote:There is also another way to make those methods become singleton methods (belonging to that module).
Just type extend self and it will take care of all of the methods defined beneath that line.
It has an advantage over module_function, it will let you use attr_ methods like those we have seen in my previous posts as if we were dealing with a class and not a module.

Keep in mind that such methods will NEVER become part of a class where you have mixed it in. You will still need to call it by typing MyModule.method_name every single time you need to trigger them there.

Right, I forgot to reveal another important fact about modules, you can call its module methods from anywhere! Once they have been properly defined, you can access them from any other script defined after that module has been defined.

Happy ArgumentError Message Debugging Nights! Laughing
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#4
Numbers
Those Boring Integers and Floats

Nope, I am not talking about a weird TV show here. Laughing Instead I want to talk about how Ruby deals with all kinds of numbers. First of all, they aren't really some primitive types as in C or C++ and many other languages. They do posses methods and you can use a dot and a method name to get some different value at any time! Shocked 

First of all, you got to know they all do not belong to a Number class, even if that would have been quite useful. Its actual name is the Numeric class. Internally Ruby offers you the Integer which is divided in Fixnum and Bignum without any way to let you ever change that. Still you can add or subtract numbers like you have always done in school. There is Float as well, which include all real numbers, those pesky values like 1.0 or 3.14159 and so on. There is no other number class. You can still enter binary or hexadecimal values but Ruby will internally print an integer instead. If you do not believe me, go try the IRB alias the Ruby Ruby Interactive Shell Console. Laughing + Tongue sticking out 

+ lets you sum up whatever you need to calculate, - is subtraction, * is multiplication and / lets you divide a number by another. % provides you with its modulo value (4 % 3 = 1 as its modulo). You can also combine them with the = equal sign at will. You can compare them with operators (mathematical symbols) like < or > or >= or <= or <=> or == or !=. <=> is the sort operator, while != is the unequal or not equal symbol.

In Ruby you normally get Integers as a result unless both of them are Floats or you explicitly define the last argument as a Float with to_f method. you can convert a Float to an Integer with the to_i method. Actually you can even convert a character like 'A' to an Integer with to_i or hex or even ord depending on your version of the Ruby interpreter.

Even so numbers in Ruby are kind of constant so you can assign 1 to 100 variables that whenever you change the value to one of them, the rest will not get affected at all, not even if you alter the original variable that was storing that number! Shocked 

Hello World!
The Most Boring Way to Start Programming

Yeah, it was inevitable! Laughing We had to come to this point some day and that day or night has finally come! Laughing + Tongue sticking out 

How do you say that in Ruby!?

That is quite easy in Ruby and Cristal, you only need to do this:

puts "Hello world!"

And it will get printed in the Console console or terminal window. Really, there is nothing else you need to do. Well, you can substitute puts with print, but you would need to add another argument, namely the return carriage symbol "\n" or your next line will be printed right at its side without any space in between. puts does that for you from the very beginning. Shocked

How do I do the same in RM series?

You would need to create a Window and its self.contents or a Sprite and its self.bitmap to do that. This is how you do that with Sprites.

Code:
@sprite = Sprite.new
@sprite.bitmap = Bitmap.new(240, 26)
@sprite.bitmap.draw_text(0, 0, 240, 24, "Hello world!")

Here I did not use self.bitmap because I was already using a variable storing that @sprite. It is practically the same with a Window but you usually use one of its subclasses like Window_Base or Window_Command or a custom window class instead. You replace bitmap with contents. draw_text, guess what? It draws text on screen for you! Laughing + Tongue sticking out For this kind of stuff you better use @instance variables, never use local variables that use no symbol prefix because they would disappear right after your method or script ends. They get killed in no time! Shocked Do not make them suffer without need! Laughing

Explanation on Bitmap and Window_Base's draw_text method

Code:
@sprite.bitmap.draw_text(0, 0, 240, 24, "Hello world!")

draw_text(x_coord, y_coord, max_width, max_line_height, text, optional_alignment)

The optional alignment there can be either non explicit which is the same as its default value 0 (left).
1 would mean it will be centered taking in consideration the lines max_width.
2 means its right hand side will end at the max_width.

puts "Happy Non Disposed Bitmaps!"
Laughing
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#5
Regular Expressions in Ruby

Well, there are people out there that say that regular expressions or regex or regexp are no extension of a programming language but a language of its own, others might say it is some kind of DSL and so on. The truth about regular expressions that you should know about is that regex are not the same in every single language because there are oddities that only belong to a specific language or group of languages.

Why are they called regular then? Confused


It is not because of something like a regular interval since it does not really look for it, even if we can ask it to return one or more occurrences of a certain string of text. It might be because you expect your favorite language to regularly look for them if you ever pass it a string. You could say it is a more complicated way of comparing stuff than usual, I mean, it is different to variable == 1 or another_variable == :symbol . Here you look for patterns.

What do you mean with patterns? Confused 

It would be stuff like /repeated/ or /[0-9]+/ or /[a-z]+/ and many more. Sometimes it is similar to comparing a string directly like in variable == 'repeated' but there also are times when you do not expect something THAT specific but a group of either numbers or characters or even a mix of them. So anything that relatively matches them would also become a valid finding for our matching system called regular expressions and its comparisons. This is something so common in programming that you always get shortcuts to some of these searches like /\d+/ for numbers (actually they are digits) or /\w+/ for characters.

Even though you might want to look for general ways to find matches, sometimes you want to confirm they are something special like people's names. In such case you could do something like /[A-Z]\w+/ to attempt to find them, if people ever cared to capitalize their own names... Happy with a sweat Sadly, Sad it might also think that some misspelled word like antiMatter is a valid name, even if we meant it to be a term used in physics only. Winking Do not worry, my friends! There is a solution! Shocked Use /^[A-Z]\w+/ instead and it will ignore antiMatter for it did not begin with a capital letter, that is what the symbol after the initial backslash does there, to deny there was any match if there is a problem at the beginning.

What if I don't care about capital letters? Confused 

In such case, you can do two things to forget about cases in strings.

Either use string.downcase for lowercase or string.upcase for uppercase.
Or just add an lowercase i to the end of the regex like in /\w+ \w+/i

'12.478'.sub(/\d+.\d+/, 'Some Float')
'12.478'.sub(/\d+\.\d+/, 'Some Float')


That is a string that would get substituted or sub'ed by another string, namely 'Some Float' and both are the same, meaning you will get the exact same result, the string to replace the former. Since all floating point numbers (real numbers) are always written with a dot in Ruby, it does not matter if you pick any of those options. The problem with the first choice is that you could also type '12,478' and it would also replace it because a dot . in a regular expression means "any character" in a single slot or caret position. Still, Ruby would not convert it to a real number because it might think that only the first match (12) matters there, but it still can replace it completely with any string of your choice.

If you are looking for temporary replacements, sub is the right method for you! sub! does the same job but it also changes the strings contents till the end of your method or application. Confused For n number of replacements use either gsub or gsub! instead.

Keep in mind that [ and ] are used as a way to group a number of candidates it will be looking for or get replaced later on. | that pipe or pipeline character (or whatever you want to call that weird symbol) means "or" and you can use it to specify that it might accept one pattern option or the other(s). ( and ) are useful if you only care to substitute or manipulate a group of characters that were specified therein. You get matches in general like this...

$1, $2, $3 and so on. Of course if the previous matching variable was the last real match ever found, the rest will be equal to nil, meaning there was nothing else to be looking for.

But how do I verify if it matches without modifying the string? Confused 

Happy with a sweat Right... I should not have forgotten to tell you all about it. Well, that is up to you. You can either use if or unless statements or a case statement.

if (condition)
unless (condition)
case number_or_string_or_symbol
when regex1
  # code
when regex2
 # code
else
 # code
end

There else is valid as a default behavior in case there is no reason to trigger a previous option. It can be used in if, unless and case ... when statements. It got to be the very last option! Shocked
By the way, unless is nothing but the negation of if. Laughing It is the same as using if !(condition) there. ! means the opposite, most of the time it equals false (or even nil in Ruby). In languages like C or C++, booleans like true and false (or even null or nullptr under some circumstances) are as useful as 1 and 0 respectively to test the true-ish nature of a test. Ruby throws the latter to the garbage can. Laughing + Tongue sticking out The reason behind it would be that Integers like 0 and 1 are true by nature in Ruby. Sarcasm + Confused It is quite weird indeed. Laughing + Tongue sticking out

What do you do if what I am testing is neither a number nor a string from the very beginning? Confused 

Shocked Right! I knew I had forgotten something as usual. Laughing + Tongue sticking out In such situations you can convert it to a string by calling the to_s or to_str or even inspect method. They always return a string! Though there is a catch as always... Happy with a sweat The former options might return a different string than the latter because they might have employed different formats to process any given object.

If you are dealing with classes, you can either call its name method or just its given name like in Scene_Map or Window_Base. Laughing + Tongue sticking out Just never use the === or identity check if you just pick their given names. Confused That also means that you should not use them in case when statements, the result would always be false. In a simple if or unless condition, you can call the is_a?(Name_Your_Class_Or_Module) method to check if that object is a copy of such class (or not).

One last thing... You might also know that =~ can be used for matches as well. Usually you place a string first and a regex later on. It will return a 0 if it is a real match or nil if you fail to find it. In that case you better do exactly what I did in my farewell message below. Then you would get an useful boolean test or true-false check!

Happy Fake ('Captain J.U. Tyler' =~ /captain/i) == 0 Match!
Laughing + Tongue sticking out
If anybody can ever believe he deserved to be a captain even of a spacecraft simulator.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#6
Variable & Constant Scope

Usually when learning OOP languages like Ruby Ruby, you end up meeting the need to care about variable scopes.
  • $global scope
  • @@class scope
    - Initialized outside where no method can be found.
  • @instance scope
    - Local to a class but can only be called by us if it's part of some method's code.
  • local scope
    - It can't escape a method's scope but can be passed on to another method as an argument.
  • block scope
    - It won't escape a block no matter what you do.
CONSTANTS belonging to any given class or module have the same scope as a @@class variable.
The only advantage the former offer is that they can be called from anywhere else via the :: scope operator.
The latter need you to define a method to grant them some access from the outside world.

Mad Scientist Before we proceed with the next topic, we need to recall something I had said earlier on this thread concerning nesting classes and modules.

Kyonides Wrote:I have seen people nesting classes and modules at will. Why’s that?

Err, well, you could say they are free to do so. For instance, you could define a single module and then lots of classes inside… like the RPG module in the maker series. Stuff like RPG::Actor and so on are a “living proof” of it. Double colon :: mean the connection there is between the container module and its inhabiting class. To be honest with you, you can do that with two different classes as well. There the difference would be that the first class might call the second class as some sort of helper class that might contain stuff you deliberately wanted to separate from the main class. RPG::Event and its subclasses are an excellent example here. The sections you can see in the event editor might belong to either the main or the secondary classes.

So far it sounds quite straightforward, right? Happy with a sweat
The truth is that it isn't. Laughing
There's a catch! Shocked
Indifferent You see, there are two ways to add a nested class or module to an existing one.

Basic Nesting

Code:
module Mod
  class Classy
    # Add some custom code here!
  end
end

Specific Class Definition

Code:
class Mod::Classy
  # Add some custom code here!
end

Happy with a sweat They look quite similar, right?

But they are not identical! Shocked

The truth is that the first one opens the module's scope first so you can add anything you can think off and later call it from anywhere inside that module or nested class without typing the whole address, i.e. you don't need to remind it of the Mod:: module name and the scope operator.

The latter behaves in a different way. Since it specified the scope from the very beginning, you can't directly access the module's methods, constants, etc. without specifying the scope as well. So you'd either need to include Mod (which is weird) or use the scope operator every single time you ever plan to call the constants' or any other object's values.

Why did this ever happen? Confused

The reason is simple. You narrowed down the scope to only keep direct access to that nested class Classy. If you had used the first declaration, the scope would have been opened to the whole module instead. This would also include what you had defined in a different script section on the RM editor. Laughing

So choose the module or class scope wisely. Nerd

By the way, Constants in Ruby Ruby are treated almost like common variables. Very happy + Tongue sticking out
The reasoning Thinking behind this would be that classes and modules got to be open for new additions at any given time.

Happy Refactoring of Your Code! Laughing
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#7
Comparisons

In Ruby you have got 3 ways to compare a value of a CONSTANT or variable with any other value.

if or unless statements (plus iterators (loops) like while and until)

Code:
if today == "Sunday"
  print "It's Sunday!"
elsif today == "Monday"
  print "How boring! It's Monday once again..."
else
  print "I just have to drive off to work, you know."
end

Here we were using the == equality operator.

By the way, unless is a negative if statement.

case statement

Code:
case $game_party.actors[0].name
when "Aluxes", "Alex", "Alexis"
  print "He's just an idiot!"
when "Basil"
  print "A fool tailgating another fool..."
when "Hilda"
  print "You should never trust a witch, you know."
end

As you can see in the example above, it's a convenient way to test things. It even allows you to add more than a single value to every single when clause. You could say it's like defining an if statement in a very convenient way.

But there's a catch! Shocked

The comparison is always made based on the call to the === identical method.

Happy with a sweat === Happy with a sweat  would return true.
Happy with a sweat === Sweat would return false, even if they look kind of similar.

An if statement won't force you to use any specific operator for comparisons, you need to define them on every single line of code you're adding to your script.

Enter ? Ternary : Condition

What's a ternary condition? Confused

Well, it's quite simple indeed. It's like an abbreviated form of an if statement. It can also be found in other languages like C and C++.
I guess you could find it useful if you need to test variables in order to find out if you set one value or another. You can also use it to call two distinct methods.

Setting a Variable's Value

Code:
legal_status = age >= 21 ? "Adult" : "Minor"

We used the >= greater than or equal to operator on the example above.

As you have noticed, the variable legal_status will return an Adult or Minor status based on a character's age.

Calling Different Methods

Code:
base_infiltrated? ? explode : business_as usual

In this case we have included three different methods to test if a hypothetical base has been infiltrated by the enemy. Dalek
If true, it will simply explode and ignore the third method. Happy with a sweat
If false, people will ignore the routine check and keep working hard at the military base. Laughing

Happy Boolean Return Values! Laughing + Tongue sticking out
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#8
More About Defining Methods

As far as you have seen here, you can defining pretty much any method except for the new method. You would have to use the initialize method if you ever need to setup what values it will define every time it creates a copy of that class, meaning it becomes a new Ruby Ruby object.

For more information on the new and initialize methods, please read the main post of this thread.

There is something I have not told you that might confuse you if you come from other languages like C or C++.

Ruby Ruby does not care about the order of the method definitions.

Until now you might have thought that you had always had to start with the class definition and the initialize method, if you ever needed it. Then you would have to define any other methods below the initialize or (scene class) main method. And that was fine.

The thing is that Ruby does not expect you to always follow that pattern. Actually it is the same for it if you first define dozens of attr_reader or attr_accessor method calls to quickly define new methods, and then come up with the definition of the initialize or main method. To be honest with you, you could also cut them all and paste them right below all of your manually defined methods.

I have got a reason why I am bringing this up right now. There is a slight advantage at defining certain methods and place them above the method that will call them later on.

Internally it seems to be more convenient for Ruby to go up to the line where the method you have called from another method is located and then return to the caller after the former method's execution has ended.

Placing the callee after the caller method seems to make it a bit slower than the process I have described above. Here is an example of what I have been talking about:

Code:
class Window_Message
  def substitute_actor_name(text)
    text.sub(/\\n\[(\d+)\]/i, $data_actors[$1.to_i].name)
  end

  def fake_message_text_processing
    text = $game_temp.message_text
    text = substitute_actor_name(text)
    self.contents.draw_text(4, 32, width - 32, 32, text)
  end
end

In that hypothetical case we are defining substitute_actor_name before we even deal with fake_message_text_processing in the Window_Message class. So when the script ever calls and process that latter, it will jump upwards and execute the former and then fall back to fake_message_text_processing method without any issues. Then it will continue executing its contents, namely the draw_text method, to display a single line of text on screen.

Recursive Methods

This type of method relies upon itself to keep processing data over and over again as if you had defined a loop or for loop or while loop or until loop.

Code:
class Window_Test < Window_Base
  def recursive_method(value, value_max)
    val_width = self.contents.text_size(value).width + 4
    self.contents.draw_text(4, 32, val_width, 32, value.to_s)
    value += 1
    recursive_method(value, value_max) if value < value_max + 1
  end
end

In the case above we have defined a new Window_Test class that inherits basic methods from the Window_Base class. That will allow us to call the draw_text method at will.

Later on we have also included a call to the very same method we are defining there. It was necessary to include a condition (the if modifier) to prevent it from recursively call itself for the rest of our lives. Otherwise we could have seen how the game gets frozen and some popup window showing up telling us that a stack overflow has occurred and the engine needs to close by force.

So if we call recursive_method(5, 10) just once, it will print the value on screen 6 times in the same line. Shocked

Confused Do you need to include recursive methods in your scripts?

Well, not really. Laughing It is up to you and your scripting needs.
Indifferent I guess not many scripts will ever demand you to implement such a thing in your game project.
Grinning Even so you can be glad to know that you have learned about another programming skill here.

Happy Helper Method's Day! Laughing + Tongue sticking out
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#9
The Lack of Interest into Fully Understanding a Programming Language

Many but many scripters around even to this day tend to misuse a feature of Ruby just because they found something similar in the default scripts. This has been true ever since RMXP came out as the first engine with some scripting capabilities and still returns every so often in VX Ace.

Defining a Class or Module

As I told you before, there is a simple way to create a class.

Code:
module MyModule
end

class MyClass
  include MyModule
end

And you can even include modules, not just one but many in a row! Just separate them by using commas.

So what's wrong with it?

Nothing. It has been correctly executed there. What I would like to criticize now is the lack of knowledge those scripters have shown over the years. It all begins with stuff like this.

Code:
class MyCommandWindow < Window_Selectable
end

Here many people fall in a trap that won't normally cause any issues except when they do it once again!
Yes, they repeat the same declaration over and over again every single time they define what we call the Parent Class or Super Class.

What it means is that MyCommandWindow is the Child Class of Window_Selectable, making it a window with menu features preincluded by default, even if they had been created in Window_Selectable only. And guess what? Window_Selectable class is a Child Class of Window_Base and the latter is the Child Class of Window!

As you can see the list can go way beyond your imagination, really it does.

But why do they keep repeating the same mistake over and over again?

That's because they lack some insight of Ruby inner workings like the C side of Ruby code. Yeah, Ruby is run on C functions. Every single Ruby Object is a special C struct.

C struct

The way I'll explain this issue is the following: declaring the class or module serves 2 main purposes.

  1. Define the class or module and its parent class or module (as in a module nested inside another module). Do this once if they do have a parent class.
  2. Reopen the class or module. That's it!

Ruby isn't like Java. The latter made it overly complicated to extend certain basic features like printing stuff on a shell or console.

Ruby just has OPEN CLASSES!

That's a nice feature that lets us add as much stuff as deemed necessary and alias (keep a reference to a preexisting method) a given method at will.

Downside: It might allow many people to rely on monkeypatching default classes as a way not to create child classes or delegate them to custom classes.

In CRuby you would use a function called rb_define_class("MyClass", rb_cObject) instead. Modules don't need a second parameter: rb_define_module("MyModule").

Internally it's used to determine if a class exists. Otherwise, it'll look for functions like rb_obj_alloc and stuff like rb_class_new and even an initializer., which can be your very own custom function or call your Ruby initialize method. A Ruby side initialize definition will certainly overwrite a C side one.

So whenever you repeat the whole statement, you keep telling the Ruby system that it should now check the parent class once again!

Why on earth!? It kept it in memory and won't forget it as long as the program is running. Thus, it makes no sense to insist on declaring that there.

And what comes next is especially directed at newcomers and slightly experienced scripters: stop doing it or you might end up making a mistake like declaring the wrong parent class!

This issue is similar to another one that keeps showing up in newcomers' codes, the excess of checks by calling too many if or unless or case statements to get to a single point where they simply need to change a variable's value, especially common whenever they need to toggle switches.


That topic might be something that should be handled in a separate post...

Happy Class Declarations! Editor 
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#10
The Other Bad Practices Found in RGSS Scripts

We all should know by now how to declare an if or unless conditional statement. Happy with a sweat Yet, there are people out there that do weird stuff while doing so. In some cases the culprit was the RMXP's default code. For those guys that entered the scene after RMVX or RMVX Ace came out, I have no excuse. Confused

Code:
if variable == true
  print "It's true!"
end
if variable == false
  print "It isn't true..."
end

This is one of the most extreme cases seen so far.

For some reason, the guy checks the same variable twice, once for a truthy value and another for its opposite value. It is terrible! Angry

Just like in many other languages, there are other ways to check the same value appropiately, without repeating oneself.

Code:
if variable == true
  print "It's true!"
elsif variable == false
  print "It isn't true..."
end

There we can see how to define a second condition using elsif instead. It certainly means "else if" there.

If we were checking for totally different values, that solution would be fine. Even so, we are only checking what is its actual boolean value and under such circumstance, there is an easier way to deal with it.

Code:
if variable == true
  print "It's true!"
else
  print "It isn't true..."
end

Yes guys! That is all you needed to do from the very beginning! Laughing
Shocked But wait! There is more you need to learn here about those statements!

Code:
if is_variable
  print "It's true!"
else
  print "It isn't true..."
end

Grinning It is quite interesting how the code still works, don't you think? Thinking
But why does it work here? Who Knows?
There is an easy explanation. In Ruby, unlike C or C++, all objects return a truthy value if they are not equal to nil of the NilClass or false for obvious reasons. In C it would be quite common to see something like the following code:

Code:
if (result) {
  return "You were successful!";
} else {
  return "You failed!";
}

The negative way to declare that kind of statement would be:

Code:
if (!state) {
  return "LoadError: Failed to load script.";
}

A ! bang, yes, a ! bang there means negative value or opposite value or simply false.

And guess what? That does exist in Ruby as well! Shocked

Code:
if !is_done
  print "In the works!"
else
  print "Done!"
end

Of course, newcomers might need to include the equality operator and the true value like this == true but in the professional world that is not used at all. The only reason why you would ever, if ever, use it would be to test if an object is equal to true or false or nil in a threefold check. And this is extremely uncommon, guys! Happy with a sweat

Toggling Switches

So how can we apply that knowledge to changing the boolean value of a Game Switch? Thinking

Just use the following code:

Code:
$game_switches[1] = !$game_switches[1]

A Curious But Nonsensical Idea

Some time ago somebody wrote me a message telling me how dangerous it would be to do the following while using modules and classes.

Code:
module Some
  ONEISTHERE = "Someone is there!"
  class Thing
    include Some
  end
end

OK, I got to say that it is idiotic per se, still, this person wanted me to warn you about it. The reasoning behind it was that it would create a terrible loop that should be avoided at all costs. Interesting conclusion. Thinking

Mad Scientist Let us test this theory, guys!

[Image: attachment.php?aid=1723]

Nope, as we can see in the picture above, that is CERTAINLY NOT the case there!

What has happened was that we simply created a "new link" to the Constants already declared in the module above.
The only thing we have achieved was to come up with a redundant way to get to the same old Constant. Laughing
It was totally unnecessary for sure. Happy with a sweat Laughing

Happy Bug Bug Causing Nights!


Attached Files
.jpg   module_class_module_summary.jpg (Size: 67.21 KB / Downloads: 31)
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }


Possibly Related Threads…
Thread Author Replies Views Last Post
   Ruby - Behind the Scenes DerVVulfman 0 1,151 07-15-2023, 05:52 PM
Last Post: DerVVulfman
Information  Assorted Ruby chm documents. hanetzer 10 35,318 08-17-2020, 04:19 AM
Last Post: kyonides
Brick  Learn Ruby! greenraven 2 7,622 05-16-2014, 12:25 PM
Last Post: greenraven
   Creating Your Own Scripting System DerVVulfman 3 7,475 10-12-2009, 03:37 PM
Last Post: Alpha-Mad
   How to make interesting NPC's without scripting Third333Strike 0 3,848 12-06-2008, 04:59 PM
Last Post: Third333Strike



Users browsing this thread: 1 Guest(s)