As mentioned on this question, there is no way to define a constant which I can redefine into a descendant.
In many of my cases, I'd like to have a constant which I can redefine. The alternatives I see to avoid a creation on each consultation which doesn't make sense would be
That's not doable
class A
feature -- Access
Default_value: STRING = "some A value"
end -- Class
class B
inherit
B
redefine
Default_value
end
feature -- Access
Default_value: STRING = "some B value"
end -- Class
Alternative with once instance_free
class A
feature -- Access
Default_value: STRING
once
Result := "some A value"
ensure
instance_free: class
end
end -- Class
class B
inherit
B
redefine
Default_value
end
feature -- Access
Default_value: STRING
once
Result := "some B value"
ensure
instance_free: class
end
end -- Class
As far as I understand, the once wouldn't be created with B value as the A class value would be taken
Alternative with attribute
class A
feature -- Access
Default_value: STRING
attribute
Result := "some A value"
ensure
instance_free: class
end
end -- Class
class B
inherit
B
redefine
Default_value
end
feature -- Access
Default_value: STRING
attribute
Result := "some B value"
ensure
instance_free: class
end
end -- Class
Would it be the only and good practice to do it?
Out of 3 mentioned possibilities, only instance-free once functions can be used because
constants are frozen and, therefore, cannot be redefined;
instance-free attributes are not supported.
One more way is to use regular functions with manifest once strings to guarantee that result is always the same:
class A feature
default_value: STRING
do
Result := once "some A value" -- Note the modifier "once".
ensure
instance_free: class
constant: Result = default_value -- Ensure the Result is constant.
end
end
However, there seems to be no particular benefit compared to instance-free once functions. (I would still keep the postcondition constant to avoid erroneous redeclaration of the feature.)
Edit. Some details for the example above:
At run-time, regular manifest strings of the form "foo" create a new string object every time they are evaluated. Once manifest strings of the form once "foo" create a new string object only for the first time instead. On subsequent evaluation, they produce the same object that was computed earlier.
Postcondition Result = f of a query f (the example uses default_value instead of f) ensures that the second call to f produces the same object as the first call. Indeed, in expression Result = f, Result refers to the object computed by the feature. The call f refers to the object computed by the second call to the feature. So, whenever we call f, it produces the same object. (Ideally, we would explicitly require that the third, fourth, etc. calls to the feature also produce the same object. However, this is beyond expressive power of the language. Formally, the equality of all results produced by f could be proved by induction.)
Related
I am trying to write a policy which governs administrator username compatibility, which consists of three rules: alphanumeric value, not part of disallowed names (admin, administrator etc.), and longer than 5 characters.
I have found that when using OPA as part of a CI pipeline (which is my use case), the most comfortable solution is to create an object (dictionary) which contains policy results so that I can query them directly. My line inside the CI pipeline will look like this:
for file in rego_directory:
opa eval -i file -d data.json "package_name.policy"
Which doesn't print all of the variables and temporary resources I use inside the rego file (which saves a lot of logs and outputs). In order to make this "policy" object, I have inside my rego file the following pattern:
policy[policy_name] = result {
policy_name :=
...
computations...
...
result := <logical condition>
}
Now, my questions are as following: This doesn't seem like a best practice to me. Is there another way to simply omit the variables from the output? previously I've worked with separate values (i.e. something like this:
default policy_1 = false
default policy_2 = false
policy_1 = {
<logical condition>
}
policy_2 = {
<logical condition>
}
Second question: How do I create an output dictionary (since JSON output of a dictionary is a nice format to work with, after all) which can satisfy multiple conditions? looking back at my example, I can't write something like this:
policy[policy_name] = result {
policy_name :=
...
computations...
...
result := <logical condition>
result := <logical condition 2>
}
Since this is double assignment, which is invalid. Even if I use = instead of :=, it creates conflicts if one term is true and the other is false, and errors are not what I'm looking for (I need boolean answers). How do I create a complex rule whose output I can put inside this dictionary?
Thanks in advance.
TLDR; to answer your questions explicitly:
Now, my questions are as following: This doesn't seem like a best practice to me. Is there another way to simply omit the variables from the output?
There's nothing wrong with having your software query for the value generated by some rule. In fact, rules are the fundamental way of defining abstractions in your policies so that you can decouple policy decision-making (i.e., the logic that produces the decision) from policy enforcement (i.e., the logic/actions taken based on the policy decision.)
The only real alternative is to query for a set of rules inside one or more packages like you showed.
Second question: How do I create an output dictionary (since JSON output of a dictionary is a nice format to work with, after all) which can satisfy multiple conditions? looking back at my example, I can't write something like this:
You're asking how to express Logical OR. In this case, you would create multiple definitions (we call them "incremental definitions" in some places) of the policy rule:
policy[policy_name] = result {
policy_name :=
...
computations...
...
result := <logical condition>
}
policy[policy_name2] = result2 {
policy_name2 :=
...
some other computations...
...
result2 := <some other logical condition>
}
This snippet defines an object (named policy) that maps policy_name to result and policy_name2 to result2. We call this kind of rule a Partial Object. You can also define Partial Sets. When you define a Partial Object, you need to ensure that each key maps to at-most-one value (otherwise you'll get a runtime error.)
Another way of structuring your policy would be to (essentially) define a deny-list using partial sets:
package usernames
deny["username must use alphanumeric characters"] {
re_match("[a-zA-Z0-9]", input.username)
}
deny["username must be at least 5 characters long"] {
count(input.username) < 5
}
deny["username is reserved"] {
reserved_usernames[input.username]
}
reserved_usernames := {"admin", "root"}
Then your CI pipeline can simply query for deny:
opa eval -i input.json 'data.usernames.deny'
The result will contain reasons why the username should not be allowed.
While learning more about Ruby, I'm currently running into a wall. I'm trying to extract and sort the value of an instance variable of one class, that's stored in an array inside an instance variable in another class. I seem to only be able to grab the instance of the class itself, rather than the specific instance variables within the class.
Below are the two classes.
product.rb
class Product
attr_reader :name,
:price
def initialize(name, price)
#name = name
#price = price
end
end
catalogue.rb
class Catalogue
attr_reader :contents
def initialize
#contents = []
end
def cheapest
#contents.product.first
end
def <<(product)
#contents << product
end
end
The following test confirms I'm not properly extracting and sorting #name nor #price for the instance of Product that's stored in #contents in the instance of Catalogue.
catalogue_test.rb
gem 'minitest', '~> 5.2'
require 'minitest/autorun'
require 'minitest/pride'
require 'catalogue'
require 'product'
class CatalogueTest < Minitest::Test
def test_cheapest_of_one
catalogue = Catalogue.new
catalogue << Product.new('scissors', 8)
assert_equal 'scissors', catalogue.cheapest
end
end
Here is the failure:
Failure:
CatalogueTest#test_cheapest_of_one [catalogue_test.rb:16]:
--- expected
+++ actual
## -1 +1 ##
-"scissors"
+[#<Product:0xXXXXXX #name="scissors", #price=8>]
Ideally, I'd like to be able to extract and sort the product based on price across a number of instances. I realize I will need to further extend the existing code to ensure I'm grabbing the cheapest (when there is more than one object in the array), but was just trying to start with a basic function to access the elements in it.
Thus far I've tried some different methods like sort and first, however, I'm unable to go beyond the above output, [#<Product:0xXXXXXX #name="scissors", #price=8>], and drill down into the instance variables. 🤷♂️
What would I need to add to catalogue.rb to make test_cheapest_of_one in catalogue_test.rb pass?
I think your test will work with the following method definition:
def cheapest
#contents.sort_by(&:price).reverse.first.name
end
or alternatively
def cheapest
#contents.sort_by { |product| produce.price * -1 }.first.name
end
Currently you're trying calling #contents.product, which is actually calling Array#product - not what you want.
In your question, you ask:
What would I need to add to catalogue.rb to make test_cheapest_of_one in catalogue_test.rb pass?
But, that is the wrong question to ask! As I alluded to in my comment above, your problem is that, in your test, you are testing whether a Product is equal to a String, which can never be true, because a Product will never be equal to a String. A Product will only be equal to a Product and a String will only be equal to a String.
So, the problem is with your test, not with the production code.
If you were to modify your production code, you would have to change the cheapest method to return the name of the cheapest product. But that is wrong. It should return the cheapest product. It doesn't help you if it returns the name, because there's nothing useful you can do with the name. You cannot print out how much the cheapest product costs, for example, because you don't know what the cheapest product is, you only know what it is called.
The correct solution is to modify the test, so that it tests that the correct product is returned, not the name:
def test_cheapest_of_one
catalogue = Catalogue.new
scissors = Product.new('scissors', 8)
catalogue << scissors
assert_equal scissors, catalogue.cheapest
end
How to use the old keyword into ensure clause of a feature, the current statement doesn't seem to be valid at runtime
relationships: CHAIN -- any chain
some_feature
do
(...)
ensure
relationship_added: attached relationships as l_rel implies
attached old relationships as l_old_rel and then
l_rel.count = l_old_rel.count
end
For the whole case, following screenshots demonstrate the case
start of routine execution
end of routine execution
There are 2 cases to consider: when the original reference is void, and when — not:
attached relationships as r implies r.count =
old (if attached relationships as o then o.count + 1 else 1 end)
The intuition behind the assertion is as follows:
If relationships is Void on exit, we do not care about count.
If relationships is attached on exit, it has one more item compared to the old value. The old value may be attached or Void:
if the old value is attached, the new number of items is the old number plus 1;
if the old value is Void, the new number of items is 1.
Several times I've found myself refactoring web application code and end up wanting to do something like this (Groovy in this case, but could be anything):
Map getData(String relationName, Integer rowId) {
def sql = Sql.newInstance([...])
def result = sql.firstRow('SELECT getRelationRow(?,?)', relationName, rowId)
sql.close()
return new HashMap(result)
}
where the stored procedure getRelationRow(relname text, rowid integer) executes dynamic sql to retrieve the row of the specified rowid in the requested relation. The best example I've seen of such a function is this polymorphic function using anyelement type, and is called as
SELECT * FROM data_of(NULL::pcdmet, 17);
However to call this in the above code would require
def result = sql.firstRow("SELECT * FROM data_of(NULL::${relationName},?)", rowId)
that is, it required the relation name to be pasted into the query, which risks SQL Injection. So is there away to keep the polymorphic goodness of the stored procedure but allow it to be called with generic relation names?
I don't think it can be done this way. I assume Groovy is using prepared statements here, which requires that input and return types are known at prepare time, while my function derives the return type from the polymorphic input type.
I am pretty sure you need string concatenation. But don't fret, there are functions like pg_escape() to sanitize table names and make SQLi impossible. Don't know Groovy, but it should have that, too.
Or does it?
Based on the function data_of(..) at the end of this related answer:
Refactor a PL/pgSQL function to return the output of various SELECT queries
With PREPARE I can make this work by declaring the return type explicitly:
PREPARE fooplan ("relationName") AS -- table name works as row type
SELECT * FROM data_of($1, $2);
Then I can hand in NULL, which is cast to "relationName" from the prepared context:
EXECUTE fooplan(NULL, 1);
So this might work after all, if your interface supports this. But you still have to concatenate the table name as return data type (and therefore defend against SQLi). Catch 22 I guess.
I'm new to Lua programming, having come over from python to basically make a small addon for world of warcraft for a friend. I'm looking into various ways of finding a section of text from a rather large string of plain text. I need to extract the information from the text that I need and then process it in the usual way.
The string of text could be a number of anything, however the below is what we are looking to extract and process
-- GSL --
items = ["itemid":"qty" ,"itemid":"qty" ,"itemid":"qty" ,]
-- ENDGSL --
We want to strip the whole block of text from a potentially large block of text surrounding it, then remove the -- GSL -- and -- ENDGSL -- to be left with:
items = ["itemdid":"qty …
I've looked into various methods, and can't seem to get my head around any of them.
Anyone have any suggestions on the best method to tackle this problem?
EDIT: Additional problem,
Based on the accepted answer I've changed the code slightly to the following.
function GuildShoppingList:GUILDBANKFRAME_OPENED()
-- Actions to be taken when guild bank frame is opened.
if debug == "True" then self:Print("Debug mode on, guild bank frame opened") end
gslBankTab = GetCurrentGuildBankTab()
gslBankInfo = GetGuildBankText(gslBankTab)
p1 = gslBankInfo:match('%-%- GSL %-%-%s+(.*)%s+%-%- ENDGSL %-%-')
self:Print(p1)
end
The string has now changed slightly the information we are parsing is
{itemid:qty, itemid:qty, itemid:qty, itemid:qty}
Now, this is a string that's being called in p1. I need to update the s:match method to strip the { } also, and iterate over each item and its key seperated by, so I'm left with
itemid:qty
itemid:qty
itemid:qty
itemid:qty
Then I can identify each line individually and place it where it needs to go.
try
s=[[-- GSL --
items = ["itemid":"qty" ,"itemid":"qty" ,"itemid":"qty" ,]
-- ENDGSL --]]
print(s:match('%-%- GSL %-%-%s+(.*)%s+%-%- ENDGSL %-%-'))
The key probably is that - is a pattern modifier that needs quoting if you want a literal hyphen. More info on patterns in the Lua Reference Manual, chapter 5.4.1
Edit:
To the additional problem of looping through keys of what is almost an array, you could do 2 things:
Either loop over it as a string, assuming both key and quantity are integers:
p="{1:10, 2:20, 3:30}"
for id,qty in p:gmatch('(%d+):(%d+)') do
--do something with those keys:
print(id,qty)
end
Or slightly change the string, evaluate it as a Lua table:
p="{1:10, 2:20, 3:30}"
p=p:gsub('(%d+):','[%1]=') -- replace : by = and enclose keys with []
t=loadstring('return '..p)() -- at this point, the anonymous function
-- returned by loadstring get's executed
-- returning the wanted table
for k,v in pairs(t) do
print(k,v)
end
If the formats of keys or quantities is not simply integer, changing it in the patterns should be trivial.