lainchan / λ
(untitled)
Hiro Protagonist · 2018-01-11 08:52
There's no Ruby (on or without rails) thread.
I'm quite comfortable with Python, but I want more dynamic shenanigans than Python can offer. I'm aware that Ruby's blocks are superior to Python lambdas, and the meta-programming capabilities of Ruby are good.
Should I give Ruby a try? Is Ruby relevant without Rails/web development?
Knuth · 2018-01-11 10:09
>Is Ruby relevant without Rails/web development?
Not really, if you don't happen to live in Japan.
They use it all over the place, there.
word · 2018-01-11 10:14
>>6081
https://www.metasploit.com
Nobody important · 2018-01-11 10:20
>Should I give Ruby a try?
Yes.
>Is Ruby relevant without Rails/web development?
As a language? Absolutely, Rails is one of the worst parts of Ruby.
Job-wise not really, unless you're allowed to write scripts with it. Almost all companies that use Ruby do so because of Rails.
Anyway, Ruby is overall a much more sound language than Python. It's daunting at first because the metaprogramming is really commonplace and you have to work out how the language works to understand it, but it all makes sense after a while.
Right now I'm writing a CMS where you have various data types defined by a DSL that looks like this:
data :Video do
id "id"
url "text"
html do
<<-HTML
<div class="video">
<iframe src="https://www.youtube-nocookie.com/embed/#{url}?rel=0"
width="360" height="200" frameborder="0" allowfullscreen></iframe>
</div>
HTML
end
end The code for turning this into a class definition is really straightforward once you understand the language.
I don't know what resource to recommend for getting comfortable with the language, I guess anything would be good enough for that, but once you've got the basics down I recommend you read Metaprogramming Ruby. The book will explain the most widely-used kinds of metaprogramming you can do with Ruby, and will give you a good understanding of the whole language.
Neuromancer · 2018-01-11 10:25
>>6083
Who uses Ruby at this level? I mean which companies/open source projects/application domains?
It seems powerful as hell indeed, I would love to give it a try.
Neuromancer · 2018-01-11 15:44
For someone who has never gotten a lot into either of them, is Ruby like Perl's hipster cousin? I always got that impression.
How related are these languages? What does Ruby offer that attracts you more than Perl?
Rick Deckard · 2018-01-11 16:24
>>6094
>For someone who has never gotten a lot into either of them, is Ruby like Perl's hipster cousin? I always got that impression. How related are these languages?
Yes, Perl was an influence for Ruby's design.
Ruby follows the Perl's motto "there's more than one way to do something", instead of enforcing a single way to solve problems as Python.
>What does Ruby offer that attracts you more than Perl?
Good support for object orientation. OO in Perl is like kicking dead whales down the beach.
Mitnick · 2018-01-11 16:35
>>6094
I don't know Perl that well, but I think their similarities are mostly syntactical. Ruby is a lot like Smalltalk underneath, so absolutely everything is an object and the things you might call "functions" are actually methods that act on a receiver object, in fact method calls are just syntactic sugar for "send" (e.g. "a".upcase can also be written as "a".send(:upcase)). There are functions in Ruby in the form of "blocks", but they're not meant to be given a name and called directly like in other languages.
As for the syntax, Ruby's was very much inspired by Perl's. Both are designed so that they can be written in a terse manner, but Perl usually ends up being much more noisy and less elegant than Ruby.
And both follow the philosophy of giving you multiple ways to do the same thing, like >>6096 mentioned.
Neo · 2018-01-11 16:48
>>6084
>Who uses Ruby at this level?
Rails uses a LOT of this kind of DSL hackery.
In ActiveRecord (often called the best part of Ruby) you just have to write a class named the same as your SQL table, and the library will automatically query the database schema to infer all the column names and generate all the corresponding methods. There's even a DSL similar to the one in my post to generate the SQL tables.
Many other libraries use similar DSLs.
>which companies
...Unfortunately most companies that use Ruby do so because of Rails, as I mentioned earlier.
>application domains
Pretty much anything that doesn't require tight optimization and/or the security of a typed language. The speed is comparable to Python, and there's an official embedded version (mruby) that you can use as scripting language for a larger project.
Unnamed · 2018-01-11 16:54
>>6098
I'll give it a try. I did some python scripting in the last year, but I find it boring as a fuarrrk. Ruby seems more fun to play with.
Cutter · 2018-01-11 17:59
>>6098
>best part of Ruby
*best part of Rails.
Dozer · 2018-01-11 22:53
I love Ruby. I used it to make a password generator for myself the other day.
Jane Doe · 2018-01-11 23:40
>Is Ruby relevant without Rails/web development?
It's a general purpose programming language. Think of it as a nicer, cleaner Perl. It's got a very rich standard library and is great for string processing and Unix scripting.
The only thing I don't like about it is the library system.
load and require work just like C's #include directive: they read the referenced file and evaluate it, affecting the global state of the interpreter. Python creates a separate name space for that file and lets you pick what names to import from it.
Ruby gems outside the language is very good, though. The gem authoring process is much nicer and intuitive than Python's. You just make a metadata file and then you can package the gem and upload it to the gem repository. Very easy and flexible.
HELIOS · 2018-01-12 00:21
>>6083
>metaprogramming resources
It's just two key concepts. The first is the idea of classes being objects. A little mind-bending at first since it implies the Object class is an instance of itself. The second is the concept of a metaclass. Everything flows from there.
Classes are objectd created via Class.new which can take a block as parameters. You can call define_method on the object and give it a block to serve as implementation. Since blocks are closures, they will remember the variables in scope, letting you easily metaprogram them.
Metaclasses are just hidden classes that sit between an object and it's actual class. When you define a "class method", you're actually defining a regular instance method on the object's meta class. It's how singleton methods are implemented.
From then on it's a matter of understanding the metaprogramming API.
Hong, Guil Dong · 2018-01-12 13:08
>>6109
There's a ton more about "metaclasses" somewhere in this pdf
https://lainchan.org/mod.php?/%CE%BB/res/2730.html#q3005
section 5 page 126ish
Dujour · 2018-01-12 13:08
oops bad link https://lainchan.org/%CE%BB/res/2730.html#q3005
Meddler · 2018-01-13 07:35
>>6117
>>6118
That's a good book. I learned a lot by reading it even though I have lots of Ruby experience.
John Peters, You Know, The Farmer · 2018-08-05 19:10
I'm making a Ruby application that helps me organize the mess that is my computer
At this point, I'm trying to do the following:
-Open a file
-Rename file once contents are seen
-Close file automatically.
I want to be able to open with any application, so I can't rely on always using the default. Additionally, the experimenting I've done with using PIDs has shown me that when I use "open", the PID I receive isn't the same as the PID of the process I end up running (I think there's a startup process for the application, then another for the actual display of the image I opened, but I'm not sure)
Here's what I have so far. Any and all help is appreciated
PNG_REGEX = Regexp.new(".*png")
path = File.expand_path("..")
print "PATH = #{path}\n"
d = Dir.new("#{path}/") #Open all png images
def is_png?(folder, filename)
return PNG_REGEX.match?(filename)
end
print "Running processes: ", Process.groups.to_s
d.each { |file|
if(is_png?(path, file))
puts "Opening... #{file}"
opened_process = IO.popen("open -g -n \"#{path}/#{file}\"")
print "Parent is #{Process.pid}"
print "Child is #{opened_process.pid}" #This changes after
# calling "open"... Not sure how to get new pid
in_str = gets #Simulate getting some input
# Close opened file after gets finishes (How?? This command doesn't actually close Preview)
Process.kill("HUP", opened_process.pid)
end
}
Lunch · 2018-08-06 18:42
>>9920
If you've tried to use "open" before outside of that script you should have noticed that it actually exits immediately rather than waiting around until the process it spawned is done. That's because it actually sends a message to launchd (which is roughly macOS's equivalent of systemd) to spawn a new process rather than spawning that process itself. Preview will not be executed as a child of open, so killing open won't do anything (especially since it will already have exited by the time you call Process.kill on it).
You could either try calling open with -W, which seems to wait until the process it opened has finished, though I don't currently have a mac on hand so I don't know whether it will relay signals to the process it opened.
You could also just spawn /Applications/Preview.app/Resources/MacOS/<binary name> (I think that's the right path) directly.
Also, a few suggestions about code style:
- Nobody uses Regexp.new. Use regexp literals instead.
- You should probably use Dir["*.png"] instead of that weird thing you wrote.
- Try to unnest your code when you can. The loop could be rewritten like this:
d.each do |file|
next unless is_png?(path, file)
...
end - Don't use interpolated string when calling a subprocess (unless you really need shell stuff), properly quoting strings for the shell is a huge pain. Pass an array instead.
John Peters, You Know, The Farmer · 2018-08-07 15:08
>>9932
Hey! Thanks so much for the response! I tried implementing what you recommended and I have a couple of observations:
-When I opened "/Applications/Preview.app/Contents/MacOS/Preview" , it works!!! I can now open and close an image at will!
My only concern now is that on certain images, I get an error from Preview saying I don't have permission to view it. This is strange to me because I'm have read+write permissions on the image (see attachment). Because of this, I won't be able to actually iterate through and call the IO.popen function correctly.
A bit more information, just in case it's helpful:
-When I do *sudo /*complete path preview executable*/ /*image*/, I get "Illegal Instruction: 4", but subsequent openings of the image don't have the permission error.
-Changing the permissions on the Preview executable didn't do anything.
Here is my updated loop code (so thanks for the suggestions! You're a life-saver!)
d.each { |file|
next unless is_png?(file)
application_name = "/Applications/Preview.app/Contents/MacOS/Preview"
input_array = [application_name, " \"" + path+"/"+file+"\""]
puts "PASSED IN: ", input_array.join(" ")
opened_process = IO.popen(input_array.join(" "))
in_str = gets #Simulate getting some input
# Close opened file after gets finishes.
Process.kill("HUP", opened_process.pid)
}
Crash Override · 2018-08-07 20:49
>>9949
Huh, I have no idea what's going on with the permissions. Maybe it has something to do with macOS' sandboxing. Sorry, I can't help you much here.
I guess you could try with another image viewer, I used to get by with an old version of Xee from back when it was still free when I used OS X.
Anyway, that's not really what I meant by passing an array to IO.popen. If you join it it's still gonna be a string interpreted by the shell, but if you actually pass in an array of the program + the arguments, it's gonna use it directly to execute the system call and you won't need to quote the path.
Something like this:
IO.popen(["ls", "/path with/spaces"]) Is gonna work better.
Drifter · 2018-08-08 03:43
Does anyone here have any experience with converting a ruby program to Crystal?
stack · 2018-08-08 05:51
>>9956
see >>9239
Judge Fang · 2018-08-09 15:10
>>9952
Again, thanks for the response!
I'm trying to do the array version, but I'm having trouble using flags in the command.
When I add flags to the command I want to run, i get "invalid option: --". I've tried a whole bunch of permutations of the input, but to no avail... Is there something I'm missing here?
d.each { |file|
next unless is_png?(file)
application_name = "Preview.app"
input_array = ["open", FLAGS , file]
puts "CURRENT FILE: ", file
puts "PASSED IN: ", input_array.join(" ")
# error: Invalid option --
opened_process = IO.popen(input_array)
John Peters, You Know, the Farmer · 2018-08-18 19:24
Really starting to enjoy Ruby.
Specifically, I'm beginning to test my application and am blown away by how much relevant info the default unit test library gives (the place I work at is the polar opposite. They give you so much information it's really difficult to read through the pages-long error log).
This is more of a beginner question, but how do you lains organize your class variables? I'm all too used to C++, so I've found that this way of organizing my variables helps me:
class ImportantClass
@descriptive_varname;
@another_variable;
# ...
end
It allows me to easily see what class variables I expect to see in the implementation of my class functions.
However, I am running into this issue. Whenever I misspell one of the variables, Ruby just continues running silently (well, using "nil" until something crashes). How can I make it such that if I have a variables I don't expect, I return an error immediately?
My idea is currently to use the attr_readers, but am not sure if that's such a good idea. Any help/insight is helpful!
Marly Krushkhova · 2018-08-18 22:21
>>9984
>is_png?(file)
It's more idiomatic to just write png? and omit the is_ prefix commonly used in other languages. Tbe boolean-ness of the result is denoted by the trailing ? so there is no need for the is_ -- the latter is only really used in languages without support for punctuation.
It'd be also elegant if you turned this function into a method of File, so that you could do:
next if file.png?
I know a multitude of ways to accomplish this, all with varying pros and cons. Last time I programmed it was on Ruby 1.9.2 -- the language's probably come a long way since then. Has support for refinements finally landed?
>>10124
>Whenever I misspell one of the variables, Ruby just continues running silently (well, using "nil" until something crashes). How can I make it such that if I have a variables I don't expect, I return an error immediately?
Use attr_accessor methods to get and set the variables.
class X
attr_accessor :var
end
This will generate var and var= methods to get and set the @var variable. If you misspell it, you get a no method error. This also serves to "declare" the variables as you say, letting you know at a glance which ones exist and at the same time wrapping them in accessor methods.
There are also attr_reader and attr_writer variants; just writing attr is equivalent to attr_reader.
>but am not sure if that's such a good idea
Why wouldn't it be? It's Ruby. Do what feels right.
John Peters, You Know, the Farmer · 2018-08-19 00:16
>>10126
Interesting!
I knew about attr_reader/writer, but had never really come across "attr_accessor"
I'm beginning to like Ruby more and more each day!
Thanks a lot!
Six · 2018-08-19 00:27
>>10127
They're just regular everyday methods of Module, which is the superclass of Class.
Church · 2018-08-19 00:33
>>10127
You can see their documentation here:
https://ruby-doc.org/core/Module.html
You should definitely check out all the methods of Module and Class. It will deepen your understanding of Ruby's object system. There's a Python-like framework in place too: the language itself will call some special methods when certain things happen, like a new class subclassing one of your classes. This allows you to metaprogram these cases.
If you haven't already, definitely check out Array, Hash, Range, Enumerable and Enumerator.
John Peters, You Know, the Farmer · 2018-08-19 02:57
>>10128
>>10129
That's awesome!!
Just to make sure I understand this:
Creating the attr_accessor methods will allow me to read and write to the variables.
Outside the class, it would simply be
instance.var_name = new_val
And inside the class it would be
self.var_name = new_val
Assuming I'm not completely wrong, would there be some way to overwrite the behavior of @var_name to call the created function?
It's pretty much a non-issue at this point, but I'd like to know if it'd be possible to avoid writing self. every time I want to safely access a variable, and using "@" would help make my code a bit more concise.
Again, thanks a lot for the help, and I'll make sure to go through the documentation more
let · 2018-08-19 04:02
>>10135
You understood it right. The following are equivalent:
class X
attr_accessor :y
end
class X
def y
@y
end
def y=(z)
@y= z
end
end
Note how the method's name is y= -- the = is punctuation just like ! and ? and these are the three "special" symbols that can appear at the end of Ruby method names.
The method call syntax also allows spaces between the name and the = symbol. For example, x.y = z is equivalent to x.y=(z) . Since this is the same syntax for assigning variables, you must use self.y = z inside the class because otherwise you'd end up creating a new local variable instead of calling the y= method.
>would there be some way to overwrite the behavior of @var_name to call the created function?
No, this is not possible as far as I know. The @var_name is special syntax and in Ruby syntax can't be overridden like in Lisp.
The @var_name syntax is equivalent to the instance_variable_get method of Object, but it's internal to the Ruby implementation. Overriding this method probably won't change how Ruby itself behaves. Now that you mentioned it, it would actually be pretty nice if Ruby allowed us to customize this behavior...
https://ruby-doc.org/core/Object.html#method-i-instance_variable_get
>I'd like to know if it'd be possible to avoid writing self. every time I want to safely access a variabl
If you'd like, you can instead define a method without = that could both get and set the variable depending on whether an argument was given.
class X
def y(*arguments)
return @y if arguments.empty?
raise ArgumentError, "Expected 0..1 arguments, got #{arguments.count}" if arguments.count > 1
@y = arguments.first
end
def initialize(value = :default)
y value
end
end
Now there's no clash with the variable assignment syntax and you don't have to use self anymore.
You can even make an attr_accessor -style method to automatically define these accessors for you.
class Module
def hybrid_accessor(*symbols)
symbols.each do |symbol|
variable = :"@#{symbol}" # :variable => :@variable
define_method(symbol) do |*arguments|
return instance_variable_get variable if arguments.empty?
raise ArgumentError, "Expected 0..1 arguments, got #{arguments.count}" if arguments.count > 1
instance_variable_set variable, arguments.first
end
end
end
end
class X
hybrid_accessor :y
def initialize(value = :default)
y value
end
end
https://ideone.com/tiihGK
John Peters, You Know, the Farmer · 2018-08-19 05:23
>>10136
Okay, so I'm reading over your second bit of code and that's exactly what I need!
I got inspired, and I got a bit curious how far I could push this idea, and came up with something I'm sort of proud of;
class X
safe_reader :test_var
safe_writer :test_var
#hybrid_accessor :test_var
def initialize(value = :default)
# @test_var= value
puts "RESULT OF ASSIGNMENT: #{test_var! (value)}"
puts self.methods
read_result = test_var_()
puts "VALUE OF test_var: #{read_result}\n\t Compare with: #{@test_var}"
if(read_result != value)
puts "uhoh"
end
end
end
https://pastebin.com/AmFMj0Wx
Now i can do my original idea, which was "private write, public reads".
I doubt I'll see *huge* improvements in readability/productivity, but I'm left very impressed with how powerful of a tool Ruby is. Metaprogramming is neat!
roll · 2018-08-19 05:36
>>10138
So you used two different methods, variable_ for readers and variable! for writers. Works well too. You can create a safe_accessors method too that just calls safe_reader and safe_writer with the same arguments.
By customizing the symbol you feed to define_method, you can create any scheme you like. For example, you could generate get_variable and set_variable! methods instead, or have a safe_boolean that generated variable? methods.
Ruby is really fun to play with.
Vasya Pupkin · 2018-08-19 05:46
>>10138
>I doubt I'll see *huge* improvements in readability/productivity
Metaprogramming like this is about avoiding repetition. Instead of defining 5 nearly identical reader and writer methods, you can define the general structure for all of them once and then supply the parameters that define each method. If you ever want to change how the accessors work, you change it only in one place instead of everywhere.
Another simple example of avoiding repetition is requiring multiple libraries in one go. You take advantage of the fact require is just a method that takes strings as parameters.
%w(net/http json base64 ostruct optparse).each { |lib| require lib }
Depending on how big your code is, you can probably factor out common parts into general methods that dynamically define your specific methods. You can make simple DSLs.
Spike Spiegel · 2018-08-21 11:49
It's a shame to see such a good versatile scripting language being generally reduced to just being the base of some web framework. Unlike Python, it actually follows my thought patterns, has a great toolchain and the documentation is just two clicks away.
It's also a shame most of the companies hire Ruby on Rails programmers and not "pure Ruby" programmers. For some reason you can do so in Python, but not Ruby. I'd probably be happier to write Ruby scripts and simple applications than Rails backend code.
Rails isn't a bad framework BTW. You can get work done in minutes (and no, I'm not talking about scaffolds here).
Judge Fang · 2018-08-22 10:45
>>10159
It's because Python had nearly a decade of advatange compared to Ruby. Python has always been popular while Ruby wasn't even on people's radar until Rails made its impact. If you like Ruby, then write your programs in Ruby. There's nothing wrong with that.
My biggest problem with Ruby is how it does libraries. Ruby gems are awesome and very easy to create, publish and use, but Ruby's require is similar to C's #include. Python and Javascript have a much cleaner, properly namespaced approach. Since I really enjoy writing lots of small libraries and combining them into a concrete program, this is annoying for me.
Dozer · 2018-09-21 09:49
I were ordered to make something in Ruby on Rails.
I'm learning it since monday, and I still don't know if it's even possible, or how to do it. (I'm python dev, with some Django background and knowledge on C++/Qt who never before used ruby)
My task is to make it possible to choose new kind of custom field in issue in redmine.
Sounds easy huh? But this custom field should be relation to ERPmine (redmine plugin) WkAccount.
Still sound easy huh? But it should be written inside plugin, and I shouldn't change anything in redmine code. because it's possible that ERPmine developers would accept my changes and it wouldn't be necessary to change redmine code every time we would update redmine
Sound uneasy, isn't it?
Is it even possible to change how new issue page, and issue edit page are rendered without changing theirs controllers and view thase are inside redmine, not inside plugin, but with writing something in plugin?
I would say that it's impossible, but my supervisor says it is.
Please give me tips.
Neuromancer · 2018-09-21 20:20
>>10475
I guess before any tips can be given, you need to give us a bit more context.
What have you attempted?
Start small, then build your way up. Search Engines are your friend.
Tackle one thing at a time, and whenever you get stuck, have a concrete idea of what exactly you want to fix is.
Tequila · 2018-09-22 21:06
what's the lainon weapon of choice for version/gem management?
RVM is a mess and I'm looking for something new.
Liet Kynes · 2018-09-22 22:29
>>6081
>Not really, if you don't happen to live in Japan.
This unfortunately is the case, which is sad to me because of how much I like that language. That shouldn't stop you from starting projects in it though
JARGON · 2018-09-27 18:32
I love Ruby. And I am very comfortable reading Ruby. It's very readable. Unless I'm reading the code of some wizard class hacker I can understand what it is doing. I don't have to like, figure out what it's doing. I can just read what it's doing.
Jim Hilger · 2018-09-28 09:59
>>10592
Ruby is quite neat, but I was tired of using R for doing statistics and I had to invest some time with Python.
I feel like knowing Ruby and Python would be redundant, so I stick with Python as my personal scripting language.
Zero Cool · 2018-09-28 21:22
Ruby is overall a better a well designed and consistent language where you always know by looking at syntax how everything is scoped. The reason Python holds on to the top spot is because its list comprehensions are so good (bear in mind that lists in Python are just arrays, so its just array iterators). The block syntax in Ruby is just soykafty and tedious how you have to use pipes for parameters and is just really a weak excuse for not having high order functions. And all the mapping, reduce, iterator functions in Ruby is just too much needless detail that could all be replaced by a single unified comprehension syntax. If Ruby were to adopt Python's comprehensions Python would get erased off the map overnight.
byte · 2018-09-30 11:51
>>10601
>The block syntax in Ruby is just soykafty and tedious how you have to use pipes for parameters and is just really a weak excuse for not having high order functions.
You can solve the same problems, just because it looks different to what you're used to is not really an argument.
>And all the mapping, reduce, iterator functions in Ruby is just too much needless detail that could all be replaced by a single unified comprehension syntax.
The reason for this is Ruby is inspired by lisp, with simple predictable syntax. Python stole list comprehensions from Haskell and in the ML world adding special context sensitive syntax with a mishmash of symbols in weird places is considered fashionable. One is not necessarily better than the other, the reason they are different is down to history and language design.
>If Ruby were to adopt Python's comprehensions Python would get erased off the map overnight.
Doubtful. The Zen of Python is There should be one — and preferably only one — obvious way to do it. Along with fewer features and strict rules about dumb things like indentation and formatting. This makes Python very popular with people who can't code and don't care about coding, they just want to hack things together that sort of works. Ruby on the other hand is all about power and choice and There's More Than One Way To Do It, which only really appeals to a subset of truly passionate developers.
hash table · 2018-10-01 20:31
>>10601
Please quit asking for list comprehensions to be added in other languages. Every fuarrrking time I see a Python fan in a discussion about other languages it's because they want list comprehensions.
Please stop, you're the only ones who think that list comprehension syntax is good and you're the only ones who find it readable. Nobody else cares.
Ishikura "Tatsu" Tatsuhiko · 2018-10-01 23:04
You could probably implement list comprehensions just fine as a Ruby DSL by introspecting a block for its source code. Either way, higher order functions are usually nicer if you're just doing operations on lists.
Ender · 2018-10-05 14:59
>>6075
I have always viewed Ruby as a better version of Python. Read "The Well Grounded Rubyist" or "Programming Ruby 1.9 & 2.0: The Pragmatic Programmers' Guide" and then "Ruby under a microscope"
Spike Spiegel · 2018-10-05 17:39
>>10740
To add to that list, I would recommend "effective ruby: rough cuts." There is a copy in the book thread.
William Holtzer · 2018-10-06 22:36
>>10651
what's the difference between lisp comprehensions and map?
word · 2018-10-06 23:06
>>10762
<not who youre quoting>
A map function is just one kind of iterator function that applies a high order function to each element of an array (or whatever kind of container type).
A list comprehension is a generic iterator that allows any kind of iterator function to work on a array/list, be it map, filter, reduce, sort or just plain iterate. Also you dont have to pass an anonymous function to a comprehension because the comprehension body is implicitly a function body. Comprehensions also allow for guard syntax which eliminates the need for if and case statements to surround map/iterator functions and themselves act as filter functions.
Iverson · 2018-10-07 08:24
>>10651
>by introspecting a block for its source code
That's not how metaprogramming in Ruby works. You could definitely write something that vaguely looks like a list comprehension, but it'd probably look a bit awkard.
Koichiro · 2018-12-20 08:22
Is there something more powerful than the default "Set" class (here: https://ruby-doc.org/stdlib-2.5.3/libdoc/set/rdoc/Set.html)? I'm looking for something like C++'s ordered_set class, where, in addition to specifying the objects I will add, I can also specify the comparison function.
I'm running into an issue where want to compare objects in a set, but when I add them to the set, it takes the object's address into account, making it so the following code returns false:
a = Tag.new("aFunnyName")
b = Tag.new("aFunnyName")
aSet = Set.new()
aSet.add(a) #Now contains {a}
aSet.include?(b) #Returns FALSE, despite a and b having the same values
While I could just do a set of strings, I'm worried about not being able to extend my "Tag" class when I decide to add a new field to the class.
One workaround is that if I simply added a "hash" function to my class, I was able to now compare values (which makes sense, seeing as though that's how the Set class adds elements) instead of the same object. However, I still run into the issue of not being to extend this if I add new fields (how would I hash both a string and an int and a floating-point number?)
Neuromancer · 2018-12-20 10:40
>>6134
What book is it? I only see a big fat smelly 404.
Cowboy · 2019-01-19 18:23
I am curious for Ruby. Has anyone gotten sacred texts? Is learning Ruby good in this world ? I shall stay with lisp perhaps
bit · 2019-01-19 21:30
How different is programming in Ruby compared to Phyton?
I don't know how to program but tried to learn Phyton before and it felt restrictive and stiff, plus it didn't make much sense. Ruby seems to be more free, and because i want to try again in the future, it seems like a good choice; in the end i don't know if programing in general is for me though.
Mario Rossi · 2019-01-19 23:36
>>12205
yeah I've tried a bunch of times to learn programming but something isn't there . I'm thinking I'll give lisp a second more committed try but recently ruby's been there too so I'm trying to choose
Agent Richard Gill · 2019-01-20 17:04
>>12205
Python enforces a "preferred way" for doing this and that. Python have one line lambdas, and poor OO support (no modifiers, etc.). Parenthesis are mandatory when invoking functions. Python is like kicking dead whales down the beach at DSLing.
In Ruby, there are more than one way for doing this and that. Ruby has blocks and meta-programming, so Ruby is freaking good at DSLing. Ruby borrows some concepts from Perl, like the backticks `` for invoking shell commands.
Delilah · 2019-01-20 17:26
>>12220
>DSL
what is DSL?
Turing · 2019-01-20 18:37
>>12221
No him but he probably means this:
https://en.wikipedia.org/wiki/Domain-specific_language
Koichiro · 2019-01-23 21:12
>>12220
Well to be fair, ',' are required for functional calls in ruby, so that's not much better. Also in what way does ruby produce DSL's? I don't see the syntax for macros, nor Haskell do syntax.
Demeere · 2019-03-26 16:33
I would like to ask for help to you great guys - experienced Rubyist/Pythonists. I modified code from book related, its finite automata that accepts all real numbers. Now what i am trying to do is to rewrite it from Ruby to Python, what i am quickly perceiving as not trivial task:
class DFA < Struct.new(:current_state, :accept_states, :rulebook)
def accepting?
puts accept_states.include?(current_state)
end
def acceptingtest?
puts accept_states.include?(current_state)
end
def read_character(character)
self.current_state = rulebook.next_state(current_state, character)
end
def read_string(string)
string.chars.each do |character|
read_character(character)
end
end
end
class DFADesign < Struct.new(:start_state, :accept_states, :rulebook)
def to_dfa
DFA.new(start_state, accept_states, rulebook)
end
def accepts?(string)
#tap evaluates the block and returns object it was called on
to_dfa.tap{ |dfa| dfa.read_string(string) }.accepting?
end
def acceptstest?(string)
#tap evaluates the block and returns object it was called on
to_dfa.tap{ |dfa| dfa.read_string(string) }.acceptingtest?
end
end
class FARule < Struct.new(:state, :character, :next_state)
def applies_to?(state, character)
self.state == state && character =~ self.character
end
def follow
next_state
end
def inspect
"#<FARule #{state.inspect } -- #{character} --> #{next_state.inspect}>"
end
end
class DFARulebook < Struct.new(:rules)
def next_state(state, character)
rule_for(state, character).follow
end
def rule_for(state, character)
if rules.detect{ |rule| rule.applies_to?(state, character) } == nil
if state==1
rules.push(FARule.new(state, character, state+1))
else
rules.push(FARule.new(state, character, state))
end
rules.detect{ |rule| rule.applies_to?(state, character) }
else
rules.detect{ |rule| rule.applies_to?(state, character) }
end
end
rulebook = DFARulebook.new([
FARule.new(2,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(3,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(4,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(5,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(7,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(8,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(9,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(1,/[1-9]/,3), FARule.new(1,/[0]/,0), FARule.new(0,/[.]/,4), FARule.new(0, /[^.]/,-1),
FARule.new(-1, /./, -1), FARule.new(1,/^[^[0-9]e[.]-]+$/,-1), FARule.new(1,/[-]/,2),
FARule.new(2,/[[:digit:]]/, 3), FARule.new(2,/[[-]]/,2),
FARule.new(3,/[[:digit:]]/,3), FARule.new(3,/[.]/,4), FARule.new(4,/[[:digit:]]/, 5),
FARule.new(5,/[[:digit:]]/,5), FARule.new(5,/[e]/,7), FARule.new(7,/[-]/,8),
FARule.new(7,/[[:digit:]]/,9), FARule.new(8,/[[:digit:]]/,9), FARule.new(9,/[[:digit:]]/,9)
])
dfa_design = DFADesign.new(1,[3,5,9],rulebook)
puts "Looking for accepting state"
dfa_design.acceptstest?('-31.24e-19')
dfa_design.acceptstest?('00.422')
end
Problem is with translating some Ruby idioms like: tap, "it evaluates object and returns block it was called on".
Also there is a lot of method chaining. For example i have problem with method follow in class FARule (FARule is one certain rule, for example: "go from state 2 to 3 if you get 'a' char") that is using method next_state DFARulebook (this class is 'container' for all defined FARules) - which for every rule in rules calls "follow" so it could go from current state to next state. As you see its quite "self-referential" and i dont know how to translate it to Python. Here is what i have so far
Also question: if i compare string to regexp by re.search(regexp, character), do i need to pass regexp as string, without typical /[something]/ syntax?
import re
class DFA:
current_state=1
accept_states=[]
rulebook = DFARulebook()
def __init__(self, current_state, accept_states, rulebook):
self.current_state=current_state
self.accept_states=accept_states
self.rulebook=rulebook
def accepting():
if current_state in accept_states:
print(true)
else:
print(false)
def read_character(character):
self.current_state = rulebook.next_state(current_state, character)
def read_string(string):
for char in string:
read_character(char)
class DFADesign:
start_state=1
accept_states=[]
rulebook=DFARulebook()
def __init__(self, start_state, accept_states, rulebook):
self.start_state=start_state
self.accept_states=accept_states
self.rulebook=rulebook
def accepts?(string):
#tap evaluates the block and returns object it was called on
dfa = DFA(start_state, accept_states, rulebook)
dfa.read_string(string)
return dfa.accepting()
class FARule:
state=1
character=""
next_state=1
def __init__(self, state, character,next_state):
self.state=state
self.character=character
self.next_state=next_state
def applies_to(self, state, regexp):
return self.state == state && bool(re.search(regexp, character))
Vasya Pupkin · 2019-03-26 16:36
>>13010
something broke, < is <, & is && (AND)
posting code again for better readability
class DFA < Struct.new(:current_state, :accept_states, :rulebook)
def accepting?
puts accept_states.include?(current_state)
end
def acceptingtest?
puts accept_states.include?(current_state)
end
def read_character(character)
self.current_state = rulebook.next_state(current_state, character)
end
def read_string(string)
string.chars.each do |character|
read_character(character)
end
end
end
class DFADesign < Struct.new(:start_state, :accept_states, :rulebook)
def to_dfa
DFA.new(start_state, accept_states, rulebook)
end
def accepts?(string)
#tap evaluates the block and returns object it was called on
to_dfa.tap{ |dfa| dfa.read_string(string) }.accepting?
end
def acceptstest?(string)
#tap evaluates the block and returns object it was called on
to_dfa.tap{ |dfa| dfa.read_string(string) }.acceptingtest?
end
end
class FARule < Struct.new(:state, :character, :next_state)
def applies_to?(state, character)
self.state == state && character =~ self.character
end
def follow
next_state
end
def inspect
"#<FARule #{state.inspect } -- #{character} --> #{next_state.inspect}>"
end
end
class DFARulebook < Struct.new(:rules)
def next_state(state, character)
rule_for(state, character).follow
end
def rule_for(state, character)
if rules.detect{ |rule| rule.applies_to?(state, character) } == nil
if state==1
rules.push(FARule.new(state, character, state+1))
else
rules.push(FARule.new(state, character, state))
end
rules.detect{ |rule| rule.applies_to?(state, character) }
else
rules.detect{ |rule| rule.applies_to?(state, character) }
end
end
rulebook = DFARulebook.new([
FARule.new(2,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(3,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(4,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(5,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(7,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(8,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(9,/^[^[0-9]e[.]-]+$/,-1),
FARule.new(1,/[1-9]/,3), FARule.new(1,/[0]/,0), FARule.new(0,/[.]/,4), FARule.new(0, /[^.]/,-1),
FARule.new(-1, /./, -1), FARule.new(1,/^[^[0-9]e[.]-]+$/,-1), FARule.new(1,/[-]/,2),
FARule.new(2,/[[:digit:]]/, 3), FARule.new(2,/[[-]]/,2),
FARule.new(3,/[[:digit:]]/,3), FARule.new(3,/[.]/,4), FARule.new(4,/[[:digit:]]/, 5),
FARule.new(5,/[[:digit:]]/,5), FARule.new(5,/[e]/,7), FARule.new(7,/[-]/,8),
FARule.new(7,/[[:digit:]]/,9), FARule.new(8,/[[:digit:]]/,9), FARule.new(9,/[[:digit:]]/,9)
])
#rulebook.next_state(1,"a")
#rulebook.next_state(1,"b")
#dfa = DFA.new(1,[3],rulebook)
#dfa.accepting?
dfa_design = DFADesign.new(1,[3,5,9],rulebook)
#(32..128).reject{|v| v=="a".ord or v=="b".ord}.each do |i|
#dfa_design.acceptstest?(i.chr)
#end
puts "Looking for accepting state"
dfa_design.acceptstest?('-31.24e-19')
dfa_design.acceptstest?('00.422')
end
setq · 2019-10-08 20:01
I got do to some Ruby at work, after having been programming in python for some time. I must say that Ruby is quite pleasant to work with, but some parts of it can't help but feel quirky, mainly because the object system takes too much space.
For examples, blocks, very good. I like them blocks. But the feel like dangling parts outside the language design.
The other strange bit is modules, which are left out in favor of classes. Maybe I'm doing it wrong, but e.g. I want to wrap functions to access external services. The clean way to do so is to have some kind of module/singleton, because you want a single initialisation in your code base, so modules seem like the way to go, except that you can't combine them easily (including a module in another one is a pain is the ass).
Also, Python seriously lacks functional programming features, but list comprehension replaces most of their basic use. And Python metaprogramming is done at a higher level, and is much easier to grasp, although I haven't tried much of it in Ruby.
nothing master · 2020-01-15 07:52
does anyone have a book they recommend for learning ruby from absolute beginner? I started with their try ruby website, but had a lot of unanswered questions.
Cowboy · 2020-01-15 17:44
Oh hell yeah. Ruby is fuarrrking great for making tools. Especially small ones.
I use a tiny pomodoro timer called thyme every day.
http://hughbien.com/thyme/
Please post more tiny ruby tools.
Stallman · 2020-01-15 17:51
>>16564
Whatever is the latest version of the Ruby Pickaxe book.
Tyrell Wellick · 2020-01-15 17:52
>>16565
Meant for
>>16554