Ruby rubocops error - assignment branch condition size too high - ruby

I've got simple method which fetch data from Jira project with assigned tasks to user which left to be done. Is there any way to downsize method below to avoid rubocop condition size too high error?
def initialize
#project = Jira::ProjectConnection.new('project_key').call
end
def assigned_task_list
project.issues.map do |issue|
next unless issue.fields.dig('status', 'name') != 'Done' && !issue.fields.dig('assignee', 'name').nil?
{
key: issue.key,
name: issue.fields.dig('assignee', 'name'),
email: issue.fields.dig('assignee', 'emailAddress'),
status: issue.fields.dig('status', 'name')
}
end
end

Perhaps like this?
def assigned_task_list
assigned_tasks.map do |issue|
fields = issue.fields
{
key: issue.key,
name: fields.dig('assignee', 'name'),
email: fields.dig('assignee', 'emailAddress'),
status: fields.dig('status', 'name')
}
end
end
private
def assigned_tasks
project.issues.select do |issue|
issue.fields.dig('status', 'name') != 'Done' &&
issue.fields.dig('assignee', 'name')
end
end

Related

JSON::ParserError in Ruby

Am trying to read data I just stored in the .json file, when running the script, am getting this error:
/Users/topazjos/.rvm/gems/ruby-3.0.0/gems/json-2.6.1/lib/json/common.rb:216:in `parse': 859: unexpected token at '[] (JSON::ParserError)
from /Users/topazjos/.rvm/gems/ruby-3.0.0/gems/json-2.6.1/lib/json/common.rb:216:in `parse'
from /Users/topazjos/Documents/SQL & Ruby Projects/school-library/savedata.rb:48:in `fetch_people_datas'
it is showing that the error is coming from thefecth_people_datas method
class IOmanager
def save_people(persons)
file = File.open('./people.json', 'a')
person_data = persons.map do |person|
if person.instance_of?(Teacher)
{ occupation: 'Teacher', name: person.name, age: person.age, specialization: person.specialization }
else
{ occupation: 'Student', name: person.name, age: person.age, parent_permission: person.parent_permission }
end
end
file.puts(JSON.generate(person_data))
end
def fetch_people_datas
return [] unless File.exist?('./people.json')
file = File.read('./people.json')
array = []
if file.empty?
array
else
person_data = JSON.parse(file)
person_data.map do |data|
if data['occupation'] == 'Teacher'
teacher = Teacher.new(data['age'], data['specialization'], data['name'])
array.push(teacher)
else
student = Student.new(data['age'], data['classroom'], data['name'], data['parent_permission'])
array.push(student)
end
end
end
array
end
end
then am calling that method like this
class CreatePeople
def initialize
#iomanager = IOmanager.new
#books = #iomanager.fetch_book_data
#persons = #iomanager.fetch_people_datas
#rentals = []
end
def create_student
puts 'Create a new student'
print 'Enter student age: '
age = gets.chomp.to_i
print 'Enter name: '
name = gets.chomp
print 'Has parent permission? [Y/N]: '
parent_permission = gets.chomp.downcase
case parent_permission
when 'n'
Student.new(age, 'classroom', name, parent_permission: false)
#persons << student
puts 'Student doesnt have parent permission, cant rent books'
when 'y'
student = Student.new(age, 'classroom', name, parent_permission: true)
#persons << student
puts 'Student created successfully'
end
end
def create_teacher
puts 'Create a new teacher'
print 'Enter teacher age: '
age = gets.chomp.to_i
print 'Enter teacher name: '
name = gets.chomp
print 'Enter teacher specialization: '
specialization = gets.chomp
teacher = Teacher.new(age, specialization, name)
#persons << teacher
puts 'Teacher created successfully'
end
def json_runner
#iomanager.save_book(#books)
#iomanager.save_people(#persons)
#iomanager.save_rental(#rentals)
end
end
I have used the same way to read from the previous file fecth_book_data inside the same class and it has worked but I don't understand what went wrong here

Ruby method refactor multi line assignment to pass RuboCop

I have been trying to tune this method that sets up complex assignment and I am looking for other options to make this function pass the cops.
Would anyone have thoughts to point me in the right direction?
Right now, I am tinkering with breaking out the two inner .map calls.
Failing Cops
Assignment Branch Condition size for parse_items is too high. [24.08/15]
def parse_items
Avoid multi-line chains of blocks.
end.compact.map do |opt|
The problem code
def parse_items
options = parse_relationships
options = options.select { |opt| opt['type'] == 'product_options' }
options.map do |opt|
parse_included.detect { |x| x['id'] == opt['id'] }
end.compact.map do |opt|
{
group_id: #payload['id'],
originator_id: opt['id'],
price: opt['attributes']['price'],
description: opt['attributes']['name'],
exp_quantity: opt['attributes']['quantity'].to_i,
title: parse_attributes['name'],
image_originator_url: 'image_for_product',
updated_at: timestamp
}
end
end
Helper Methods
private
def parse_data
#payload['data']
rescue
[]
end
def parse_included
#payload['included']
rescue
[]
end
def parse_attributes
#payload['data']['attributes']
rescue
[]
end
def parse_relationships
#payload['data']['relationships']['options']['data']
rescue
[]
end
def timestamp
Time.parse(parse_attributes['updated_at'])
end
Updated Errors
In the spec: wrong number of arguments (given 2, expected 1) for Failure/Error: SELECT = ->(opt) { opt['type'] == 'product_options' }
Assignment Branch Condition size for parse_items is too high. [17/15]
Updated Code
SELECT = ->(opt) { opt['type'] == 'product_options' }
MAP = ->(opt) { parse_included.detect { |x| x['id'] == opt['id'] } }
def parse_items
parse_relationships.select(&SELECT).map(&MAP).compact.map do |opt|
{
group_id: #payload['id'],
originator_id: opt['id'],
price: opt['attributes']['price'],
description: opt['attributes']['name'],
exp_quantity: opt['attributes']['quantity'].to_i,
title: parse_attributes['name'],
image_originator_url: 'image_for_product',
updated_at: timestamp
}
end
end
I was able to refactor this making it far cleaner and pass all the cops! Hooray!
def parse_items
assign_item_attributes(select_included_option(select_item_options(parse_relationships['options']['data'])))
end
def select_included_option(options)
options.map do |opt|
parse_included.detect { |x| x['id'] == opt['id'] }
end
end
def assign_item_attributes(options)
options.compact.map do |opt|
{
group_id: #payload['id'],
originator_id: opt['id'],
price: opt['attributes']['price'],
description: opt['attributes']['name'],
exp_quantity: opt['attributes']['quantity'].to_i,
title: parse_attributes['name'],
image_originator_url: parse_image,
updated_at: parse_timestamp
}
end
end
def select_item_options(options)
options.select { |opt| opt['type'] == 'product_options' }
end

Ruby: Playing MP3s based on if statement

I have a ruby application/website where users can scan qr codes and make donations to bitcoin wallets. Whenever a donations occurs a transaction and event is created and the bitcoins wallet value is updated. Here is the code below
require 'date'
module Server
class Event
include DataMapper::Resource
property :id, Serial
property :duration, Float, required: true, default: ->(x, y) { 1.0 }
property :created_at, DateTime, required: true, index: true, default: ->(x, y) { DateTime.now }
property :valve, Integer, required: true
belongs_to :transaction, index: true
belongs_to :bucket, index: true
def self.register(wallet, amount, hash)
bucket = Bucket.first(wallet: wallet)
unless bucket
raise DataMapper::ObjectNotFoundError, "Bucket not found for wallet #{wallet}"
end
tr = Transaction.create!({
wallet: wallet,
amount: amount,
thash: hash,
created_at: DateTime.now
})
ev = Event.create!({
valve: bucket.valve,
duration: calculate_duration(amount * bucket.multiplier),
transaction: tr,
bucket: bucket,
created_at: tr.created_at
})
bucket.update(amount: bucket.amount + amount)
end
def amount
self.transaction { |x| x.amount }
end
def self.calculate_duration(amount)
[[amount, Config.server.min_duration].max, Config.server.max_duration].min
end
def simple
return {
valve: valve,
duration: duration_millis
}
end
def duration_millis
(duration * 1000).to_i
end
def to_hash(is_simple)
if is_simple
simple
else
attributes.merge simple
end
end
def self.latest(valve = nil)
if valve.nil?
Event.first(order: [:created_at.asc])
else
Event.first(order: [:created_at.asc], valve: valve)
end
end
def self.latest!(valve = nil)
result = self.latest(valve)
result.destroy unless result.nil?
result
end
end
end
There are 3 wallets total. so 0, 1 & 2. My question is how can I play a specific sound depending on what wallet is updated using an if statement after the bucket update function is called.

include and If statement inside a for each

Clients can upload up to three files. I want to set the status of the file based on the description they choose. The upload works fine and a static status is fine, but a dynamic one raises an error.
def build_document_objects
[:first, :second, :third].each do |doc|
d = "#{doc}_document"
if self.send("#{d}_type") == "this Type"
doc_status = 'one'
else
doc_status = 'two'
self.send("#{d}=", user.documents.new(
description: "Foo",
file: self.send("#{d}_file"),
document_type: self.send("#{d}_type"),
status: doc_status
))
end
end
end
When I run this, I get the following exception:
undefined method `save'' for nil:NilClass'))
If I do this:
def build_document_objects
[:first, :second, :third].each do |doc|
# "first_document"
d = "#{doc}_document"
if self.send("#{d}_type") == "this Type"
doc_status = 'one'
else
doc_status = 'two'
end # change where the IF ends
self.send("#{d}=", user.documents.new(
description: "Foo",
file: self.send("#{d}_file"),
document_type: self.send("#{d}_type"),
status: doc_status
))
end
end
if the file description is not this type, the records will be saved. However, with:
if self.send("#{d}_type") == "this Type"
I get the exception. The record will not be saved as there is no status present.
It appears I am nuts
def build_document_objects
[:first, :second, :third].each do |doc|
# "first_document"
d = "#{doc}_document"
if self.send("#{d}_type") == "this Type"
doc_status = 'one'
else
doc_status = 'two'
end # change where the IF ends
self.send("#{d}=", user.documents.new(
description: "Foo",
file: self.send("#{d}_file"),
document_type: self.send("#{d}_type"),
status: doc_status
))
end
end
works fine
the if just needs to be in the method properly.

How to limit test data creation when running two tests with FactoryGirl

I have 48 records being created by FactoryGirl, the records use sequence so that they are all unique.
When I run a test, I get all 48 records being created with names as follow Skill_1 to Skill_48.
When I run a subsequent test, I get an additional 48 records created, these have different new values, Skill_49 to Skill_96
I really want my 2nd test to use the same data set as the first test but cannot figure out how to do so.
I have worked out that the data is RE-CREATED every time, but the sequence does not reset and so the names are different on every run
I've included my code here
# Factory
FactoryGirl.define do
factory :skill do
provisioned true
trait :skill do
skill true
end
trait :language do
language true
end
trait :qualification do
qualification true
end
trait :role do
role true
end
trait :personal_attribute do
personal_attribute true
end
sequence :name do |n|n
type = '(skill)'
if language
type = '(language)'
end
if qualification
type = '(qualification)'
end
if role
type = '(role)'
end
if personal_attribute
type = '(personal_attribute)'
end
"skill#{n} #{type}"
end
end
end
UNIT TEST is HERE
describe SkillQueryService do
let(:skills) { create_list(:skill, 10, :skill) }
let(:languages) { create_list(:skill, 2, :language) }
let(:qualifications) { create_list(:skill, 3, :qualification) }
let(:roles) { create_list(:skill, 4, :role) }
let(:personal_attributes) { create_list(:skill, 5, :personal_attribute) }
let(:unprovisioned_skills) { create_list(:skill, 10, :skill, :provisioned => false) }
let(:unprovisioned_languages) { create_list(:skill, 2, :language, :provisioned => false) }
let(:unprovisioned_qualifications) { create_list(:skill, 3, :qualification, :provisioned => false) }
let(:unprovisioned_roles) { create_list(:skill, 4, :role, :provisioned => false) }
let(:unprovisioned_personal_attributes) { create_list(:skill, 5, :personal_attribute, :provisioned => false) }
context 'sugguest' do
it 'returns 20 suggested provisioned skills' do
# Build TEST data
service = SkillQueryService.new
rows = service.suggest('skill')
# rows.each do |r|
# display_skill(r)
# end
# THIS CODE PRINTS OUT SKILLS 1-48
expect(rows.length).to eq(20)
end
it 'returns 20 suggested (UN)-provisioned skills' do
# Build TEST data
full_data_set
service = SkillQueryService.new
rows = service.suggest('skill')
# rows.each do |r|
# display_skill(r)
# end
# THIS CODE PRINTS OUT SKILLS 49-96
# HOW do I get it to have the same data as above, SKILLS 41-48
expect(rows.length).to eq(20)
end
end
def full_data_set
skills
languages
qualifications
roles
personal_attributes
unprovisioned_skills
unprovisioned_languages
unprovisioned_qualifications
unprovisioned_roles
unprovisioned_personal_attributes
end
def display_skill(skill)
PL.kv 'name', skill.name
PL.kv 'provisioned', skill.provisioned
PL.kv 'skill', skill.skill
PL.kv 'language', skill.language
PL.kv 'qualification', skill.qualification
PL.kv 'role', skill.role
PL.kv 'personal_attribute', skill.personal_attribute
PL.line
end
def display_skills
PL.line
Skill.all.each do |r|
display_skill(r)
end
end
end
I found my answer here
how-can-i-reset-a-factory-girl-sequence
before(:each) do
FactoryGirl.reload
end

Resources