Running a .rb file in Chief


tlinder
 Share

Go to solution Solved by Alaskan_Son,

Recommended Posts

I'm trying to run a .rb file that's on my local in CA by using a marco. Right now I can only get it to read the file. Does anyone have any insight on how I might be able to to this or where I need to look?

 

Macro: In CA

File.read("C:/Users - Desktop/scope1.rb")

 

 

Output: from text stored on a local drive

rafter_length = (length.to_f.round / 12) + 1

convert_to_int =  rafter_length.even?

case
  when convert_to_int == true
  resut = rafter_length

  when convert_to_int == false
  result = rafter_length +1
end

 

image.thumb.png.cead1fc53c54f9b5db1e2d8aa77354ed.png

 

Link to comment
Share on other sites

You should just make this an evaluated macro in chief, context: owner

 

 

rafter_length = (length.to_f.round / 12) + 1

convert_to_int =  rafter_length.even?

case
  when convert_to_int == true
  result = rafter_length

  when convert_to_int == false
  result = rafter_length +1
end

 

Using an rb in this case is superfluous.  IAE, to use one you would need to "require" it in your chief macro and then call any specific "defined" function within that rb file.  The only reason for using an rb file is for utility functions that aren't otherwise available that you would need in many different user macros.  This one is object specific to any object that has a "length" attribute.

Link to comment
Share on other sites

3 minutes ago, Joe_Carrick said:

You should just make this an evaluated macro in chief, context: owner

 

 

rafter_length = (length.to_f.round / 12) + 1

convert_to_int =  rafter_length.even?

case
  when convert_to_int == true
  result = rafter_length

  when convert_to_int == false
  result = rafter_length +1
end

 

Using an rb in this case is superfluous.  IAE, to use one you would need to "require" it in your chief macro and then call the "defined" function within that rb file.

Thanks Joe

The macro works in evaluated, just trying to take it one step further and save the company a lot of time.

I'm am trying to read it from my local so I don't have to open every CA file and update them 1 by 1. We have hundreds of files.

Link to comment
Share on other sites

9 minutes ago, tlinder said:

Thanks Joe

The macro works in evaluated, just trying to take it one step further and save the company a lot of time.

I'm am trying to read it from my local so I don't have to open every CA file and update them 1 by 1. We have hundreds of files.

You don't read the rb file.  You "require" it.  Within that file you need to define the function"int_length"and then in your macro you call the function.

ie:  

  • result = int_length(length)

 

Link to comment
Share on other sites

Here's a sample rb file that has a series of defined methods.  Note that I no longer use this since it's problematical to update with each new version of chief.

 

#=================================================
# Joe's Macro Subscription Service
#   Ruby script: Float Class     
#   Copyright October 1, 2015 by Joseph P. Carrick
#=================================================
# The contents of this Ruby Macro is not to be
# revealed to any other Chief Architect user or 
# employee.  If a violation of this requirement
# is found, the offending subscriber's
# subscription will be immediately terminated.
#=================================================
# Place this file in Chief Architect/Data/Scripts
# folder.  Then place the following:
#    require "Float Class.rb"
# at the beginning of any macro where you want to
# use these methods
#=================================================
 
class Float
    #=================================================================
    # Display a numerical value formatted according the the current
    # units of the Plan.  Requires $Units to be either "Imperial" or
    # "Metric" to recognize the units.
    #=================================================================
    def format_number(n)
        if $Units.nil?
            result = self.sig(3)
        elsif $Units == "Imperial"
            result = self.ftin(32)
        elsif $Units == "Metric"
            result = self.meters(n)
        else
            nvalue = self.sig(3)
        end
        return result
    end

    #=================================================================
    # Display a value (decimal inches) formatted as a text string
    #    syntax:  nvalue.ftin(denominator)
    #    example: n = 64.125
    #             s = n.ftin(8)  ->  5'-4 1/8"
    #=================================================================
    def ftin(denominator)
        if $Units.nil?
            nvalue = self
        elsif $Units == "Imperial"
            nvalue = self
        elsif $Units == "Metric"
            nvalue = self/2.54
        else
            nvalue = self
        end
        arr = self.divmod(12)
    if arr[1] >= 11.96875
      arr[0] = arr[0]+1
      arr[1] = 0.00
    end
    
        inch_frac = ((arr[1]-arr[1].floor)*denominator).round.quo(denominator)
    
        if arr[0].floor < 1
            if inch_frac == 1.0
                result = "#{arr[1].ceil}"+'"'
            elsif inch_frac == 0.0
                result = "#{arr[1].floor}"+'"'
            elsif inch_frac < 1 and arr[1].floor > 0
                result = "#{arr[1].floor} #{inch_frac}"+'"'
            elsif inch_frac < 1
                result = "#{inch_frac}"+'"'
            else
                result = "#{arr[1].floor} #{inch_frac}"+'"'
            end
        else
            if inch_frac == 1.0
                result = "#{arr[0]}'-#{arr[1].ceil}"+'"'
            elsif inch_frac == 0.0
                result = "#{arr[0]}'-#{arr[1].floor}"+'"'
            else
                result = "#{arr[0].floor}'-#{arr[1].floor} #{inch_frac}"+'"'
            end
        end
        return result
    end

    #=======================================
  # Convert Float to Feet
  #  rounded to nearest foot
  #=======================================
  def feet
      feet = (self/12).round(0).to_s
        result = feet +"'-0"
      return result+'"'
  end    

    #=======================================
  # Convert Float to Decimal Feet
  #  rounded to 3 decimal places
  #=======================================
  def decimal_feet
      feet = (self/12).round(3).to_s + "'"
      return feet
  end    

    #=======================================
  # Convert Float to Inches-Fractions
  #  Formats are:
  #    1/16"
  #    1 1/16"
  #    1"
  # nDivisor can be any integer between
  #    1 and 32.  Most common are:
  #               1,2,4,8,16 & 32
  #=======================================
  def inches(nDivisor)
      inches = self.floor
    if inches > 0.00
      frac = (self.remainder(inches)*nDivisor).round.quo(nDivisor)
    else
      frac = (self * nDivisor).round.quo(nDivisor)
    end
      if frac == 1
          result = "#{inches + 1}"
      elsif frac == 0 
          result = "#{inches}"
      else
          result = "#{inches} #{frac}"
      end
      return result.gsub(" ","-")+'"'
  end    

    #=================================================================
    # Get the SqRt of a number to n significant places
    #=================================================================
    def sqrt(n)
      a = self
        x = 1.00000
        while (x*x) < a
          x = x+0.00001
        end
        return x.round(n)
    end
    
  #=================================================================
    # Display a decimal value as a text string to (n) significant places
    #    syntax:  nvalue.sig(n)
    #    example: x = 65.375
    #             s = x.sig(4) ->  '65.3750'
    #    example: x = 65.25
    #             s = x.sig(3) ->  '65.250'
    #=================================================================
    def sig(n)
        nPad = self.round().to_s.length + n + 1
        result = self.round(n).to_s.ljust(nPad,"0")
        return result
    end

    #=================================================================
    # Convert millimeters to meters & display to (n) significant places
    #    syntax:  nvalue.meters(n)
    #    example: x = 6543
    #             s = x.meters(3) ->  '65.430 m'
    #    example: x = 650
    #             s = x.meters(3) ->  '6.500 m'
    #=================================================================
    def meters(n)
        if $Units.nil?
            nvalue = self
        elsif $Units == "Imperial"
            nvalue = self*2.54
        elsif $Units == "Metric"
            nvalue = self
        else
            nvalue = self
        end
        if n > 3
            n = 3
        elsif n < 0
            n = 0
        end
        m = nvalue/100
        result = m.sig(n).to_s + " m"
        return result
    end

end


 

  • Upvote 1
Link to comment
Share on other sites

40 minutes ago, tlinder said:

I'm am trying to read it from my local so I don't have to open every CA file and update them 1 by 1. We have hundreds of files.

wouldn't you have to open every file anyway to actually use the new functions you wish to define in the .rb file?

Link to comment
Share on other sites

Quote

Here's a sample rb file that has a series of defined methods.  Note that I no longer use this since it's problematical to update with each new version of chief.

Thank you Joe I will do some more research I this. I appreciate all your help!

Link to comment
Share on other sites

1 hour ago, jasonn1234 said:

wouldn't you have to open every file anyway to actually use the new functions you wish to define in the .rb file?

Initially yes, but for future updates I can just change the macro on the .rb file and it automatically updates the file when they are opened. 

Link to comment
Share on other sites

  • Solution

I would suggest making a handful of changes to your current approach:

  1. Add your desired folder to the $LOAD_PATH OR place the desired file inside your currently defined $LOAD_PATH.  This way you can just use a file name instead of having to use the whole folder structure.
  2. Define a method inside your rb file
  3. Use require as Joe already mentioned instead of using File.read
  4. Call your defined method inside your Chief macro.

All said and done, it would look more like this (using your originally supplied example):

 

Macro: In CA

require 'scope1'

my_method

 

 

Output: from text stored on a local drive

def my_method

 

rafter_length = (length.to_f.round / 12) + 1

convert_to_int =  rafter_length.even?

case
  when convert_to_int == true
  resut = rafter_length

  when convert_to_int == false
  result = rafter_length +1
end

 

end

 

NOTE:  There are other potential approaches and corrections that could be made as well, but I wanted to stay as close as reasonably possible to your original attempt.

Link to comment
Share on other sites

I think there's a bit more that needs to be done to make it work correctly:

 

Macro: In CA

require 'scope1'

my_method(length)

 

 

Output: from text stored on a local drive

def my_method(x)

 

   rafter_length = (self.to_f.round / 12) + 1

   convert_to_int =  rafter_length.even?

   case
      when convert_to_int == true
        result = rafter_length

      when convert_to_int == false
        result = rafter_length +1
    end

 

end

 

Unless I'm wrong, the parmeter length needs to be passed to my_method in order for the method to know what's being analyzed.  

 

Link to comment
Share on other sites

3 hours ago, solver said:

rafter_length = (length.to_f.round / 12) + 1

rafter_length.even? ? rafter_length : rafter_length + 1

Thank you for the easier format and the YouTube videos. You gained yourself a new subscriber!

 

Quote

Are you looking for standard lumber lengths?

Yes I'm just trying to have the standard lumber lengths populate in the rafter labels.

Link to comment
Share on other sites

 

14 minutes ago, Joe_Carrick said:

Macro: In CA

require 'scope1'

my_method(length)

 

 

Output: from text stored on a local drive

def my_method(x)

 

   rafter_length = (self.to_f.round / 12) + 1

   convert_to_int =  rafter_length.even?

   case
      when convert_to_int == true
        result = rafter_length

      when convert_to_int == false
        result = rafter_length +1
    end

 

end

Joe and Michael

I tried both of those approaches and I wasn't able to get the right output in Chief.

Link to comment
Share on other sites

Just now, tlinder said:

 

Joe and Michael

I tried both of those approaches and I wasn't able to get the right output in Chief.

 

Did you set the macro to Evaluated:Owner?  And did you move your script to a folder in the $LOAD_PATH or adjust the $LOAD_PATH to add your desired folder?

Link to comment
Share on other sites

5 minutes ago, Alaskan_Son said:

 

Did you set the macro to Evaluated:Owner?  And did you move your script to a folder in the $LOAD_PATH or adjust the $LOAD_PATH to add your desired folder?

Are you saying to create a folder and name it $LOAD_PATH? I'm not sure what you mean.

Link to comment
Share on other sites

2 minutes ago, solver said:

 

What did you get?

Evaluation Error: Ruby SecurityError: Insecure operation - require

Stack Trace:

from (eval):2:in `block (3 levels) in <main>'

from (eval):1:in `instance_eval'

from (eval):1:in `block (2 levels) in <main>'

from eval:9:in `eval'

from eval:9:in `block (2 levels) in <main>'

from eval:3:in `loop'

from eval:3:in `block in <main>'

Link to comment
Share on other sites

33 minutes ago, Joe_Carrick said:

Unless I'm wrong, the parmeter length needs to be passed to my_method in order for the method to know what's being analyzed. 

 

1 minute ago, Joe_Carrick said:

You probably need to set the Ruby Safe Level to 1.  CA by default sets it at 2 which doesn't allow some things to work.

 

Neither of these things are true.  You can indeed define and call a method with no arguments, and if the file is a valid rb file located within the $LOAD_PATH, you can even have a Safe Level of 4 and it should still work.

Link to comment
Share on other sites

8 minutes ago, Alaskan_Son said:

 

 

Neither of these things are true.  You can indeed define and call a method with no arguments, and if the file is a valid rb file located within the $LOAD_PATH, you can even have a Safe Level of 4 and it should still work.

Agreed- except that AFAIK, Chief's default Safe Level has always been 2

 

I do have some macros that create, read and write files.  Some of those require a Safe Level of "0".

Link to comment
Share on other sites

For rb files that you wish to use in multiple versions of Chief you will need to make sure you copy them to the current version's $LOAD_PATH.

-or-

put them in a common file and edit the $LOAD_PATH in the current version of Chief.  I'm pretty sure you can have multiple paths separated by simi-colons

Link to comment
Share on other sites

If I remember correctly, i think I tested the load path about 12 months ago and could not get it to work. Instead If I remember correctly, I put a function in the "tutorial.rb" file and it worked.

 

Although tutorial.rb is distributed by CA so it will be overwritten on installation, probably ok for testing but not long term

Link to comment
Share on other sites

There's no good reason to be placing code into the tutorial.rb file in my opinion.  Its just a messy and confusing kludge.  All you're actually doing by placing code in the tutorial file is bypassing the require line because Chief is pre-programmed to automatically load that tutorial.rb file.  You can easily replace the functionality by just using require in a text macro of your own though so you don't have to fool around with defining your methods in the tutorial file. 

 

Just create and display that macro somewhere in your template plan and all the methods defined inside your appropriately required rb files will be loaded into global memory just as if you had placed them in the tutorial file. Or require the desired rb file(s) inside specific macros.  Either way, just load them yourself (using require) instead of using the tutorial file workaround.

Link to comment
Share on other sites

Thank you for the YouTube video Eric.

 

Is there a way to define a new $LOAD_PATH to a different drive. I ask this because, I'm not the only one that is going to be opening these files.

To my knowledge they all need to be "required" from the same file path. 

Link to comment
Share on other sites

54 minutes ago, solver said:

I still do not understand what you are trying to accomplish -- big picture, not how to run ruby from outside a Chief file. If you could explain, you would probably get better help.

 

My overall goal is to create a macro in Chief to require a .rb file that is stored from a folder on a shared drive. I don't want to put it in my scripts folder that is connected to Chief because that drive (C: drive) is not shared. Instead IT is creating a new drive (Z: drive) for us, so everyone will have the same file path. There are many computers that will be opening the files in Chief.

 

I need to be specific with my file path and it needs to point to the Z: drive

 

I hope this helps.

 

For ex:

C: drive

- not shared

- where Chief is currently installed

 

Z: drive - IT created

- shared

- this is where I want to store my scope1.rb

- same file paths on every computer

 

Link to comment
Share on other sites

21 minutes ago, solver said:

Why do you want to do this rather than placing the same code in the plan file?

 

We have over 200 template files. If I placed them in every file and that macro changes, I would have to update every macro in every file manually. I'm trying to prevent re-entry.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share